From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001
From: Sven Eisenhauer
+Neben den bisher vorgestellten Datenstrukturen des Pakets java.util
+gibt es in java.lang
+eine Klasse System,
+die eine Reihe nützlicher Hilfsmittel zur Verfügung stellt.
+Die wichtigsten von ihnen sollen in den folgenden Abschnitten besprochen
+werden.
+
+
+
+
+
+In Java gibt es keine Möglichkeit, direkt auf die Umgebungsvariablen
+eines Programms zuzugreifen. Ein solcher Zugriff wurde von den Java-Designern
+als nichtportabel angesehen und statt dessen durch das Konzept der
+Properties ersetzt. Properties sind Listen von Eigenschaften,
+die dem Programm vom Java-Laufzeitsystem zur Verfügung gestellt
+werden. Jede Eigenschaft besitzt einen Namen, unter dem auf sie zugegriffen
+werden kann. Das Java-Laufzeitsystem stellt standardmäßig
+die folgenden Properties zur Verfügung:
+
+
+
+Tabelle 16.2: Standard-Properties
+Für den Zugriff auf diese Eigenschaften steht die Klasse Properties
+aus dem Paket java.util
+zur Verfügung. Sie bietet die Möglichkeit, Property-Listen
+zu erzeugen, mit Werten zu füllen und vorhandene Werte auszulesen.
+Die Klasse Properties
+ist eine Ableitung der Klasse Hashtable
+und stellt damit eine Tabelle von Schlüssel-/Wertepaaren dar.
+
+
+Für den Zugriff auf einzelne Properties reicht meist die einfach
+zu bedienende Klassenmethode getProperty
+der Klasse System
+in java.lang
+aus:
+
+
+Die erste Variante liefert die Eigenschaft mit dem Namen key
+in Form einer Zeichenkette. Falls keine Eigenschaft mit diesem Namen
+gefunden wurde, wird null
+zurückgegeben. Die zweite Variante erlaubt die Übergabe
+eines Standardwertes. Der Unterschied zur ersten Variante besteht
+darin, dass nicht null,
+sondern der Standardwert zurückgegeben wird, wenn die gesuchte
+Eigenschaft nicht gefunden wurde.
+
+
+Die Methode getProperties
+liefert das komplette Properties-Objekt
+mit den System-Properties:
+
+
+Das folgende Programm gibt eine Liste aller System-Properties auf
+dem Bildschirm aus. Es verwendet dazu zunächst die Methode getProperties,
+um das System-Properties-Objekt
+zu beschaffen. Anschließend erzeugt es durch Aufruf von propertyNames
+einen Enumerator, mit dem alle Schlüsselwerte durchlaufen werden
+können und mit dem durch Aufruf von getProperty
+der zugehörige Wert ermittelt werden kann. Auf diese Weise listet
+das Programm alle verfügbaren System-Properties auf (das sind
+in der Regel sehr viel mehr als die plattformübergreifend spezifizierten):
+
+
+
+
+
+
+ Titel
+ Inhalt
+ Suchen
+ Index
+ DOC
+ Handbuch der Java-Programmierung, 5. Auflage
+
+ <<
+ <
+ >
+ >>
+ API
+ Kapitel 16 - Utility-Klassen I
+
+
+
+
+
+16.3 Die Klasse System
+
+
+
+
+16.3.1 System-Properties
+
+
+
+
+
+
+Property
+Bedeutung
+
+java.version
+Java-Versionsnummer
+
+java.vendor
+Herstellerspezifische Zeichenkette
+
+java.vendor.url
+URL (also ein Internet-Link) zum Hersteller
+
+
+java.home
+Installationsverzeichnis
+
+java.class.version
+Versionsnummer der Java-Klassenbibliothek
+
+
+java.class.path
+Aktueller Klassenpfad
+
+os.name
+Name des Betriebssystems
+
+os.arch
+Betriebssystem-Architektur
+
+os.version
+Versionsnummer des Betriebssystems
+
+file.separator
+Trennzeichen für die Bestandteile eines
+Pfadnamens
+
+path.separator
+Trennzeichen für die Laufwerksangabe
+eines Pfadnamens
+
+line.separator
+Zeichenkette für Zeilenschaltung
+
+user.name
+Name des angemeldeten Benutzers
+
+user.home
+Home-Verzeichnis
+
+user.dir
+Aktuelles Arbeitsverzeichnis
+
+java.vm.specification.version
+Version der VM-Spezifikation
+
+java.vm.specification.vendor
+Hersteller der VM-Spezifikation
+
+java.vm.specification.name
+Bezeichnung der VM-Spezifikation
+
+java.vm.version
+VM-Version
+
+java.vm.vendor
+Hersteller der VM
+
+java.vm.name
+Name der VM-Implementierung
+
+java.specification.version
+Version der Spezifikation der Laufzeitumgebung
+
+
+java.specification.vendor
+Hersteller der Spezifikation der Laufzeitumgebung
+
+
+java.specification.name
+Bezeichnung der Spezifikation der Laufzeitumgebung
+
+
+
+
+
+
+
+
+
+public static String getProperty(String key)
+public static String getProperty(String key, String default)
+
+
+
+java.lang.System
+
+
+
+
+
+
+
+
+
+public static Properties getProperties()
+
+
+
+java.lang.System
+
+
+
+Listing 16.4: Ausgeben der System-Properties
+
+
+
+
+
+001 /* Listing1604.java */
+002
+003 import java.util.*;
+004
+005 public class Listing1604
+006 {
+007 public static void main(String[] args)
+008 {
+009 Properties sysprops = System.getProperties();
+010 Enumeration propnames = sysprops.propertyNames();
+011 while (propnames.hasMoreElements()) {
+012 String propname = (String)propnames.nextElement();
+013 System.out.println(
+014 propname + "=" + System.getProperty(propname)
+015 );
+016 }
+017 }
+018 }
+
+
+Listing1604.java
+
+In den vorangegangenen Kapiteln wurde schon häufig der Aufruf +System.out.println +verwendet, um Daten auf die Standardausgabe bzw. in ein Debug-Fenster +auszugeben. Diese Anweisung ruft die Methode println +des Objekts out +der Klasse System +auf. Dabei ist out +eine statische Variable vom Typ PrintStream, +die beim Starten des Programms so initialisiert wird, dass ihre Ausgabe +auf die Standardausgabe geleitet wird. + +
+Analog zu out +gibt es die statischen Variablen err +und in. +Dabei dient err +zur Ausgabe von Fehlermeldungen, und in +ist ein Standardeingabekanal, der dazu verwendet werden kann, Eingaben +von der Tastatur zu lesen. + +
+Mit Hilfe der Methoden setIn, +setOut +und setErr +ist es sogar möglich, die Standardein- und -ausgabe aus dem Programm +heraus umzuleiten: +
+
+
++public static void setIn(InputStream in) + +public static void setOut(PrintStream out) + +public static void setErr(PrintStream err) ++ + |
++java.lang.System | +
+
![]() |
+
+
+ +Die Verwendung dieser Klassenvariablen ist im Grunde genommen nicht +konform mit dem Dialogkonzept einer GUI-Anwendung. Ihr Einsatz kann +aber immer dann sinnvoll sein, wenn Java-Programme geschrieben werden +sollen, die keine ausgefeilte Oberfläche benötigen. In diesem +Fall sind sie ein nützliches Hilfsmittel, um einfache Ein-/Ausgaben +ohne großen Aufwand realisieren zu können. Bereits in Kapitel 3 +wurde gezeigt, wie man diese Routinen zur Ein- und Ausgabe verwenden +kann. Weitere Informationen darüber sind in Kapitel 19 +zu finden, das sich mit Byte-Streams beschäftigt. |
+
+
|
+![]() |
+
+Auch Aufrufe der Methode System.exit +sind uns schon begegnet: +
+
+
++public static void exit(int status) ++ + |
++java.lang.System | +
+Mit System.exit +wird das laufende Programm beendet. Der Aufrufparameter status +dient als Fehleranzeige und wird als Exitcode an den Aufrufer des +Programms zurückgegeben. Gemäß Konvention zeigt dabei +ein Wert größer oder gleich 1 einen Fehler während +der Programmausführung an, während 0 ein fehlerfreies Programmende +signalisiert. +
+
![]() |
+![]() |
+
+
+ +Neben der Methoden System.exit +bietet die weiter unten beschriebene Klasse Runtime +auch die Methode System.halt +an, bei der die Virtuelle Machine sofort angehalten wird. Im Unterschied +zu Runtime.halt werden dabei +weder finalize -Methoden noch +finally-Zweige abgearbeitet. +Dies kann - z.B. beim Zugriff auf eine Datenbank - dazu führen, +dass externe Ressourcen nicht zurückgegeben werden. Sie sollten +deshalb auf die Verwendung von Runtime.halt +verzichten. |
+
+
|
+![]() |
+
+
+
++public static void gc() ++ + |
++java.lang.System | +
+Ein Aufruf der Methode gc +führt einen expliziten Aufruf des Garbage Collectors +durch. Dieser sucht dann nach freiem Speicher und gibt diesen an das +Laufzeitsystem zurück. Normalerweise ist ein Aufruf dieser Methode +nicht erforderlich, denn der Garbage Collector läuft ständig +als niedrig priorisierter Thread im Hintergrund. Der Aufruf von gc +ist immer dann sinnvoll, wenn eine explizite Kontrolle über den +Zeitpunkt der Speicherfreigabe gewünscht ist. + + + + +
+Die Methode currentTimeMillis +liefert die Anzahl der Millisekunden, die zum Zeitpunkt des Aufrufs +seit Mitternacht des 1.1.1970 vergangen sind: +
+
+
++public static long currentTimeMillis() ++ + |
++java.lang.System | +
+
![]() |
+
+
+ +Ob dabei tatsächlich eine Auflösung von einer Millisekunde +erreicht wird, ist von der konkreten Java-Implementierung abhängig. +In PC-basierten Java-Systemen orientiert sie sich meist an der Auflösung +des System-Timers. Dieser wird 18,2 mal pro Sekunde aufgerufen, so +dass die Auflösung damit bei etwa 55 ms. liegt. |
+
+
|
+![]() |
+
+Mit dem folgenden Beispielprogramm kann die Auflösung des System-Timers +ermittelt werden: + + +
+
+
+
+001 /* Listing1605.java */
+002
+003 public class Listing1605
+004 {
+005 public static void main(String[] args)
+006 {
+007 long t1, t2;
+008 int actres, sumres = 0, i = 0;
+009 while (true) {
+010 ++i;
+011 t1 = System.currentTimeMillis();
+012 while (true) {
+013 t2 = System.currentTimeMillis();
+014 if (t2 != t1) {
+015 actres = (int)(t2 - t1);
+016 break;
+017 }
+018 }
+019 sumres += actres;
+020 System.out.print("it="+i+", ");
+021 System.out.print("actres="+actres+" msec., ");
+022 System.out.print("avgres="+(sumres/i)+" msec.");
+023 System.out.println("");
+024 try {
+025 Thread.sleep(500);
+026 } catch (InterruptedException e) {
+027 //nichts
+028 }
+029 }
+030 }
+031 }
+
+ |
++Listing1605.java | +
+Das Programm bestimmt zunächst die aktuelle Systemzeit und merkt +sich den Wert in der Variablen t1. +Nun wird die Systemzeit in einer Schleife erneut so oft gemessen, +bis sie sich geändert hat. Die Differenz zwischen beiden Werten +wird als Auflösung des aktuellen Durchgangs angesehen und der +Variablen actres zugewiesen. +
+
![]() |
+
+
+ +Um eine größere Genauigkeit zu erzielen, führt das +Programm die Bestimmung der Auflösung mit Hilfe der äußeren +Schleife viele Male durch. Die dabei jeweils ermittelte Auflösung +wird in der Variablen sumres +addiert und durch Division durch die Anzahl der Schleifendurchläufe +zur Ermittlung des gleitenden Durchschnitts verwendet. Das so errechnete +Ergebnis pendelt sich tatsächlich bereits nach wenigen Durchläufen +auf den vorausgesagten Wert von 55 ms. ein: |
+
+
|
+![]() |
+
+it=1, actres=60 msec., avgres=60 msec. +it=2, actres=50 msec., avgres=55 msec. +it=3, actres=50 msec., avgres=53 msec. +it=4, actres=50 msec., avgres=52 msec. +it=5, actres=50 msec., avgres=52 msec. +it=6, actres=50 msec., avgres=51 msec. +... +it=65, actres=50 msec., avgres=55 msec. +it=66, actres=50 msec., avgres=55 msec. +it=67, actres=50 msec., avgres=55 msec. +it=68, actres=60 msec., avgres=55 msec. +it=69, actres=60 msec., avgres=55 msec. +it=70, actres=60 msec., avgres=55 msec. ++ +
+
![]() |
+![]() |
+
+
+ +Interessanterweise bietet die Methode sleep +der Klasse Thread +(sie wird in Abschnitt 22.2.4 +beschrieben) auf aktuellen SUN-JDKs unter Windows mit etwa 1 ms. eine +wesentlich höhere Auflösung als currentTimeMillis. +Diese Eigenschaft ist allerdings nicht dokumentiert und kann von Interpreter +zu Interpreter sehr unterschiedlich sein. Selbst auf ein und derselben +Java-Maschine kann es durch unterschiedliche Lastsituationen zu Abweichungen +kommen. Das folgende Programm ermittelt die Auflösung von sleep: |
+
+
|
+![]() |
+
+
+
+
+001 /* Listing1606.java */
+002
+003 public class Listing1606
+004 {
+005 public static long testSleep(int millis)
+006 {
+007 final int MINDURATION = 3000;
+008 int cnt = (millis >= MINDURATION ? 1 : MINDURATION/millis);
+009 long start = System.currentTimeMillis();
+010 for (int i = 0; i < cnt; ++i) {
+011 try {
+012 Thread.sleep(millis);
+013 } catch (InterruptedException e) {
+014 }
+015 }
+016 long end = System.currentTimeMillis();
+017 return (end - start) / cnt;
+018 }
+019
+020 public static void main(String[] args)
+021 {
+022 final int DATA[] = {345, 27, 1, 1962, 2, 8111, 6, 89, 864};
+023 for (int i = 0; i < DATA.length; ++i) {
+024 System.out.println("Aufruf von sleep(" + DATA[i] + ")");
+025 long result = testSleep(DATA[i]);
+026 System.out.print(" Ergebnis: " + result);
+027 double prec = ((double)result / DATA[i] - 1.0) * 100;
+028 System.out.println(" (" + (prec > 0 ? "+": "") + prec + " %)");
+029 }
+030 }
+031 }
+
+ |
++Listing1606.java | +
+Ein Aufruf unter dem JDK 1.4 auf einem Windows-98-System im Leerlauf
+ergab folgendes Ergebnis:
+
+
+Aufruf von sleep(345)
+ Ergebnis: 343 (-0.5797101449275366 %)
+Aufruf von sleep(27)
+ Ergebnis: 27 (0.0 %)
+Aufruf von sleep(1)
+ Ergebnis: 1 (0.0 %)
+Aufruf von sleep(1962)
+ Ergebnis: 1920 (-2.1406727828746197 %)
+Aufruf von sleep(2)
+ Ergebnis: 2 (0.0 %)
+Aufruf von sleep(8111)
+ Ergebnis: 8080 (-0.3821970163974897 %)
+Aufruf von sleep(6)
+ Ergebnis: 6 (0.0 %)
+Aufruf von sleep(89)
+ Ergebnis: 89 (0.0 %)
+Aufruf von sleep(864)
+ Ergebnis: 860 (-0.462962962962965 %)
+
+
+
+
+
+
+
+Als letzte Methode der Klasse System +soll arraycopy +vorgestellt werden: +
+
+
++public static native void arraycopy( + Object src, int src_position, + Object dst, int dst_position, + int length +) ++ + |
++java.lang.System | +
+arraycopy +kann dazu verwendet werden, Arrays oder Teile davon zu kopieren. Dabei +können die Elemente sowohl innerhalb desselben Arrays als auch +in ein anderes Array kopiert werden. Falls innerhalb desselben Arrays +kopiert wird, dürfen sich Quell- und Zielbereich auch überlappen. +Die Methode arbeitet sowohl mit elementaren als auch mit Objekttypen, +Ziel- und Quellarray müssen lediglich zuweisungskompatibel sein. +Da die Methode in C bzw. Assembler implementiert ist, arbeitet sie +recht performant. + +
+Als erste Argumente werden das Quellarray src +und die Startposition src_position +angegeben. Anschließend folgen das Zielarray dst +und die Zielposition dst_position. +Als letztes Argument wird die Länge length +des zu kopierenden Bereichs angegeben. Falls die Argumente auf Elemente +zeigen, die außerhalb des Arrays liegen, wird eine Ausnahme +des Typs ArrayIndexOutOfBoundsException +ausgelöst. Falls ein Element aufgrund eines Typfehlers nicht +gespeichert werden kann, gibt es eine Ausnahme des Typs ArrayStoreException. + +
+Das folgende Programm zeigt die Verwendung von arraycopy +an einem einfachen Beispiel: + + +
+
+
+
+001 /* Listing1607.java */
+002
+003 public class Listing1607
+004 {
+005 public static void main(String[] args)
+006 {
+007 int[] ar = {0,0,0,0,0,0,0,0,0,0};
+008
+009 for (int i = 0; i < 10; ++i) {
+010 System.arraycopy(ar,0,ar,1,9);
+011 ar[0] = i;
+012 }
+013 System.out.print("ar = ");
+014 for (int i = 0; i < 10; ++i) {
+015 System.out.print(ar[i] + " ");
+016 }
+017 System.out.println("");
+018 }
+019 }
+
+ |
++Listing1607.java | +
+Das Programm füllt ein 10-elementiges Array von Ganzzahlen, das
+zunächst nur Nullen enthält, mit den Zahlen 0 bis 9. Dabei
+wird jeweils durch Kopieren der ersten neun Elemente an die zweite
+Position des Arrays an der ersten Position Platz gemacht, um dort
+den Inhalt des fortlaufenden Schleifenzählers abzulegen. Nach
+10 Durchläufen stehen somit die Zahlen 0 bis 9 verkehrt herum
+im Array. Die Ausgabe des Programms ist:
+
+
+ar = 9 8 7 6 5 4 3 2 1 0
+
+
+
| Titel + | Inhalt + | Suchen + | Index + | DOC + | Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 + |
| << + | < + | > + | >> + | API + | © 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de + |