16 Ressourcen 16 - 1 Ressourcen Inhalt Applets in Archiven Dateien als Ressourcen Images, Icons und Sound Programmeinstellungen Internationalisierung Serialization Übungsaufgaben Applets in Archiven Wir haben bisher Applets Klasse für Klasse auf dem Server abgelegt. Alle Klassen, die das Applet benötigt, werden dann vom Server geladen, wenn sie zum ersten Mal verwendet werden. Dies führt zu lästigen Verzögerungen beim Programmablauf. Nach Java 1.1 gibt es daher die Möglichkeit, Applets in komprimmierten Archiven zu laden. Solche Archive werden mit einem Zip-Programm gepackt und enthalten alle Klassen, die zum Ablauf nötig sind. Das JDK liefert einen Packer namens jar mit, der Archive mit der Endung jar erzeugt. Die Kommandozeilen-Syntax ist jar cf archive.jar *.class ... Falls Ihr Applet eigene Pakete verwendet, so sollten diese Klassen in den entsprechenden Unterverzeichnissen ebenfalls mit eingepackt werden. Das Applet-Tag in der HTML-Datei muß dann folgendermaßen erweitert werden: <APPLET CODE="Appletname.class" WIDTH="348" HEIGHT="322" ALIGN="BOTTOM" ARCHIVE="archive.jar"> Ihr Browser ist nicht java-f&auml;hig! </APPLET> Dies hat zusätzlich den Vorteil, daß nur eine einzige Datei auf den Server geladen werden muß. Sie können solche Archive auch für lokale Applikationen verwenden. Dazu setzen Sie den Classpath auf das Archiv und starten das Programm. Am Beispiel von HelloWorld.java : javac HelloWorld.java jar cf HelloWorld.jar HelloWorld.class set CLASSPATH=HelloWorld.jar del HelloWorld.class 16 Ressourcen 16 - 2 java HelloWord Wie man sieht, bezieht die Applikation nun alle Klassen aus dem Archiv. Diese Methode eignet sich besonders, um Applikationen auf anderen Rechnern zu installieren. Es ist nichts anderes zu tun, als das jar-File (man kann auch Zip verwenden) auf den Rechner zu kopieren und vor dem Programmstart den CLASSPATH zu setzen. Übrigens kann man auch mehrere Archive in den CLASSPATH aufnehmen. Dies erleichtert die Installation von Zusätzen, wie etwa den Ressourcen. Dateien als Ressourcen Ressourcen sind Dateien und Einstellungen, die von einem Programm zu seiner Konfiguration benötigt werden. Dateien können zum Beispiel Texte, Grafiken und Sound enthalten. Einstellungen sind Paare von Schlüsseln und Zeichenketten und werden auch in Dateien abgelegt. Alle diese Dateien können entweder neben den Klassendateien auf der lokalen Festplatte abgelegt, oder mit in das Archiv gepackt werden. Man kann natürlich Dateien auf der lokalen Platte oder auf dem Server mit den Methoden laden, die im Kapitel über Kommunikation beschrieben wurden. Dabei mußte man immer unterscheiden, ob das Programm als Applet vom Server oder lokal als Applikation gestartet wurde und entsprechend die Dateien auffinden. Eine Möglichkeit ist, es zunächst mit einer Datei im aktuellen Verzeichnis zu versuchen, und bei einer Exception die Datei im Netz aufzufinden. Einfacher geht es jedoch, wenn man die Datei als Ressource anspricht. Java sucht dann selbständig im Klassenpfad nach der Datei und findet die Datei auch in gepackten Archiven. Das wesentliche Merkmal einer Ressource ist, daß sie nicht vom Programm geändert werden kann (read only). Es existieren daher keine Schreibzugriffe auf Ressourcen-Dateien. Als erstes demonstrieren wir das Öffnen einer Textdatei als Ressource. Das folgende Programm zeigt eine Textdatei in einem Dialogfenster an. Dies kann zum Beispiel zur Anzeige von Hilfetexten benutzt werden. Die nächste Version von Java wird ein komplettes Hilfesystem mit Links enthalten. Bis dahin ist dies (neben der Dokumentation in einer HTML-Datei) eine Möglichkeit, Hilfe anzubieten. Der entscheidende Teil ist, einen Stream zum Lesen von der Datei zu bekommen. Dazu wird die Methode getResourceAsStream(filename) von Class benutzt. Class ist eine allgemeine Klasse, die Klasseninformationen enthält. In diesem Fall benutzen wir eine Instanz von Class, die sich auf die aktuelle Klasse Help bezieht. Diese Instanz bekommen wir mit getClass(), einer Methode, die jedes Objekt hat. Class benutzt eigentlich seinen ClassLoader, der ja die Klassen von der Platte oder aus dem Archiv laden kann. Dieser ClassLoader kann deswegen auch Ressourcen laden. Man muß noch beachten, daß Ressourcen-Dateien relativ zum aktuellen Verzeichnis, das als Wurzelverzeichnis "/" angegeben wird, bezeichnet werden. class Help extends Frame implements ActionListener { TextArea V; Button Close; // display the help from the file named subject 16 Ressourcen 16 - 3 public Help (String subject) { super("Help"); addWindowListener( // to close properly new WindowAdapter () { public void windowClosing (WindowEvent e) { dispose(); } } ); // TextArea to display the text: V=new TextArea(); V.setEditable(false); // Read the file from the resource: try { BufferedReader in=new BufferedReader(new InputStreamReader( getClass().getResourceAsStream("/"+subject))); // read line after line: while (true) { String s=in.readLine(); if (s==null) break; V.append(s+"\n"); } in.close(); } catch (Exception e) { V.setText("Could not find the help file!"); } // Layout: setLayout(new BorderLayout()); setSize(500,400); add("Center",V); Panel p=new Panel(); p.add(Close=new Button("Close")); Close.addActionListener(this); add("South",p); setVisible(true); } public void actionPerformed (ActionEvent e) // close dialog { if (e.getSource()==Close) { setVisible(false); dispose(); } } } Dem Konstruktor von Help wird der Dateiname (z.B. "help.txt") als Parameter übergeben. Zu beachten ist noch, daß als Stream auf die Ressource null zurückgegeben wird, wenn die Ressource nicht existiert. 16 Ressourcen 16 - 4 Images, Icons und Sound Auf die gleiche Art und Weise kann man auch Images und Sounds laden. Wir haben schon Bilder aus einer Datei geladen. Applets tun dies einfach mit der getImage-Methode. Falls die Datei als Ressource angesprochen werden soll, kann man anstatt des Dateinamen einfach eine Ressourcendatei an getImage übergeben. Als Beispiel erzeugen wir einen Frame, der ein eigenes Icon (unter Windows als kleines Bild links oben im Fenster) anzeigt. Dieses Icon ist eine kleine Datei mit folgendem Inhalt: Es handelt sich um eine 32x32-Pixel große GIF-Datei. Der Code für das Warten auf die Beendigung des Ladens wurde schon im Kapitel über Animation besprochen. Man beachte außerdem, daß das Programm auch funktionieren soll, wenn die Ressource nicht vorhanden ist. class AppleFrame extends Frame { public AppleFrame () { super("Appleset"); setSize(300,300); seticon("iapple.gif"); setVisible(true); } // load image and set icon: public void seticon (String file) { try { Image i=Toolkit.getDefaultToolkit().getImage( getClass().getResource("/"+file)); MediaTracker mt=new MediaTracker(this); mt.addImage(i,0); mt.waitForAll(); setIconImage(i); } catch (Exception e) {} } } Leider enthält der Code für das Setzen von Icons in jeder Java-Version vor 1.1.6 einen Fehler, der unter Windows die Anwendung verhinderte. Außerdem soll die Java 1.1 Preview-Version von Netscape einen Fehler enthalten, der das Laden von Images als Ressource verhindert. In diesem Fall kann man das Image aus einer Datei laden. Im Falle einer lokalen Datei verwendet man dazu getToolkit().getImage(file); oder (wenn man die Datei relativ zum Verzeichnis haben will, in dem sich die Hauptklasse befindet) getToolkit().getImage(System.getProperty("user.dir")+ System.getProperty("file.separator")+file); Dabei ist file der Name der Datei. Die beiden Systemeigenschaften vorher werden in Kürze 16 Ressourcen 16 - 5 erklärt. Sie besorgen sich das aktuelle Directory. Vom Netz (etwa aus einem Applet) lädt man das Image mit getToolkit().getImage(new URL(getCodeBase(),file)) Allerdings kann man mit Netscape auch den folgenden Code verwenden. try { InputStream in=getClass().getResourceAsStream("/"+Filename); byte b[]=new byte[in.available()]; in.read(b); I=Toolkit.getDefaultToolkit().createImage(b); } catch (Exception e) { System.out.println(e); } Dieser Code öffnet einen Eingabestrom und liest die Bytes der Datei in ein Byte-Array ein. Von dort wird erst das Image erzeugt. Bezüglich Sound-Dateien gilt, daß die aktuelle Java-Version nur eine undokumentierte Sound-Schnittstelle für Applikationen hat. Applets haben allerdings die Methode play, die eine Audio-Datei auf dem Server abspielen kann. Verwendet wird hier das au-Format von Sun. Erst zukünftige Versionen werden komfortablere Routinen zum Abspielen (oder auch Aufnehmen) von Sounds enthalten. Als Ressourcen lassen sich Sounds so nicht angeben. Hier soll nun die undokumentierte Schnittstelle zum Abspielen von Sounds verwendet werden. Die Sounds werden in Ressourcen-Dateien gespeichert. public void play (String filename) { try { AudioStream AS=new AudioStream( getClass().getResourceAsStream("/"+filename)); AudioData Data=AS.getData(); AudioDataStream A=new AudioDataStream(Data); A.reset(); AudioPlayer.player.start(A); } catch (Exception e) {} } Zu beachten ist, daß das Paket sun.audio.* importiert werden muß. Programmeinstellungen Programmeinstellungen lassen sich am leichtesten als Zeichenketten in Dateien speichern. Solche Einstellungen betreffen etwa Flags, die den Programmablauf steuern. Es wird hier zunächst angenommen, daß die Einstellungen vom Benutzer geändert werden können. Diese Dateien werden daher nicht als Ressourcen behandelt. Will man Einstellungen einlesen, die nicht änderbare Ressourcen sind, so kann man natürlich auf diese Dateien wie oben beschrieben zugreifen. Bei Menütexten oder auszugebenden Meldungen sollte man allerdings erwägen, die Internationalisierungstools zu verwenden, die weiter unten beschrieben werden. 16 Ressourcen 16 - 6 Zunächst werden Einstellungen in Instanzen von Properties gespeichert. Dieser Datentyp ist ein Kind von Hashtable. Es existieren allerdings Funktionen zum Lesen und Schreiben auf Streams. Angenommen, es existiert die Datei test.properties mit den Einstellungen Test.file=test.txt Test.read=true Dann stehen links vom Gleichheitszeichen die Schlüssel und rechts die Werte der Ressourcen. Z.B. hat "Test.file" den Wert "test.txt". Das folgende Programm liest nun diese Datei ein, ergänzt eine neue Einstellung und speichert sie wieder ab. import java.util.*; import java.io.*; public class Test { public static void main (String args[]) { try { Properties P=new Properties(); // Lies Properties ein: FileInputStream in=new FileInputStream("test.properties"); P.load(in); in.close(); // Drucke einige Properties: System.out.println(P.getProperty("Test.file")); System.out.println(P.getProperty("Test.files")); System.out.println(P.getProperty("Test.files","no value")); System.out.println(toBoolean(P.getProperty("Test.load","false"))); // Fuege eine Property hinzu P.put("Test.save","false"); // Speichere die Properties wieder ab: FileOutputStream out=new FileOutputStream("test.properties"); P.save(out,"Test Properties"); out.close(); } catch (Exception e) {} } public static boolean toBoolean (String s) // Intepretiere true oder false { return s.equals("true"); } } Die Funktion toBoolean intepretiert nur den String true oder false. Bei getProperty kann man einen Default-Wert übergeben. Dieser Wert wird genommen, wenn die Property nicht definiert ist. Ansonsten würde in diesem Fall null übergeben. Die Ausgabe des Programms ist folgendermaßen: test.txt null no value true Die Datei test.properties wird dabei verändert. Übrigens wird dabei der Java-interne 16 Ressourcen 16 - 7 Zeilenumbruch verwendet. Außerdem enthält die Datei nun eine Header mit dem übergebenen String und dem Datum. #Test Properties #Mon ... Test.load=true Test.file=test.txt Test.save=false Die Datei läßt sich natürlich nun als Property-Datei wiederverwenden. Einige Properties werden vom System vorgegeben und sind mit Hilfe der System-Klasse erreichbar. Das folgende Programm listet alle diese System-Properties auf. Es zeigt außerdem, wie man eine Enumeration aller Keys in einer HashTable bekommt. import java.util.*; public class Test { public static void main (String args[]) { Properties P=System.getProperties(); Enumeration e=P.keys(); while (e.hasMoreElements()) { String key=(String)e.nextElement(); String value=(String)P.get(key); System.out.println(key+"="+value); } } } Die Ausgabe dieses Programm auf meinem System ist folgende: user.language=de java.home=c:\jdk1.1.6\bin\.. java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi awt.toolkit=sun.awt.windows.WToolkit file.encoding.pkg=sun.io java.version=1.1.6 file.separator=\ line.separator= user.region=DE file.encoding=8859_1 java.compiler=symcjit java.vendor=Sun Microsystems Inc. user.timezone=ECT user.name=Rene os.arch=x86 os.name=Windows NT java.vendor.url=http://www.sun.com/ user.dir=D:\java\rene\kurs java.class.path=... java.class.version=45.3 os.version=4.0 path.separator=; user.home=C:\ Einige dieser Properties sind sehr gut für Applikationen verwendbar. Z.B. läßt sich die verwendete Java-Version abfragen. Weiter oben haben wir schon file.separator und user.dir verwendet. 16 Ressourcen 16 - 8 Internationalisierung Java-Programme sollen leicht auf jedem Rechner der Welt einsetzbar sein. Bei der Ein- und Ausgabe von Texten haben wir schon die Verwendung von Datei-Encoding kennengelernt. Nun gibt es aber weit mehr nationale Einstellungen, wie Zahlenformate, Datum usw. Außerdem soll ein Programm Menütexte und Fehlermeldungen internationalisieren. Zu diesem Zweck verwendet Java die Klasse Locale . Diese Klasse hat statische Methoden zum Setzen und Abfragen der eingestellten Sprache. Solch eine Spracheinstellung wird mit einem String aus zwei kleinen Buchstaben, sowie wahlweise einem Unterstrich und einer weiteren Beschreibung, angegeben. Ein Beispiel ist "de" oder "de_DE" für Deutsch oder "en_US" und "en_GB" für englische Sprachräume. Der eingestellte Sprachraum ist nun dafür verantwortlich, wie etwa Zahlen formatiert werden. Die Klasse, die Zahlen formatiert, ist NumberFormat. Man kann nicht direkt eine Instanz dieser Klasse anlegen, sondern benötigt dazu deren statische Methode getInstance() (und Vewandte). Mit Hilfe einer Instanz (die auch mit einem anderen Sprachraum initialisiert werden kann), kann man Zahlen lokal formatieren. Als Beispiel vergleichen wir englische und deutsche Ausgaben. import java.util.*; import java.text.*; public class Test { public static void main (String args[]) { // lokale Ausgabe (hier deutsch) NumberFormat number=NumberFormat.getInstance(); System.out.println(number.format(Math.PI)); number.setMaximumFractionDigits(16); System.out.println(number.format(Math.PI)); number.setGroupingUsed(true); // Gruppiert Dreiergruppen von Zahlen System.out.println(number.format(1000000000.01)); // englische Ausgabe (US Format): number=NumberFormat.getInstance(new Locale("en","US")); System.out.println(number.format(Math.PI)); number.setMaximumFractionDigits(16); System.out.println(number.format(Math.PI)); number.setGroupingUsed(true); System.out.println(number.format(1000000000.01)); } } Die Ausgaben unterscheiden sich durch die Verwendung von Komma und Punkt. Allerdings kann auch ein lokaler Computer anders eingestellt worden sein. 3,142 3,141592653589793 1.000.000.000,01 3.142 3.141592653589793 1,000,000,000.01 Offenbar ist der Sprachraum auch wichtig für Zahleingaben. Dazu fügen wir folgende Zeilen 16 Ressourcen 16 - 9 hinzu try { double x=number.parse(number.format(1000000000.01)).doubleValue(); System.out.println(x); } catch (ParseException e) {} Die Ausgabe zeigt, daß ein Formatierer seine eigenen Ausgabe lesen kann (auch wenn sie z.B. Gruppierungen enthält). Zurückgegeben wird ein Objekt Number, dessen Methoden man zur Umformatierung in Zahlen verwenden kann. Alternativ kann man Double.valueOf( number.parse(number.format(1000000000.01)).toString()).doubleValue(); verwenden. Dies macht zunächst aus Number einen String, den es mit Double.valueOf in ein Double umwandelt. Double ist die Wrapper-Klasse für double. Solche Wrapperklassen haben wir schon verwendet, um Zahlen in Vektoren zu speichern. Anschließend wird der Wert aus diesem Double ausgelesen. Es existieren auch Formatierer für Währungseinheiten, Prozentwerte und Daten. Wir demonstrieren alle drei in einem Programm. import java.util.*; import java.text.*; public class Test { public static void main (String args[]) { NumberFormat price=NumberFormat.getCurrencyInstance(); NumberFormat percent=NumberFormat.getPercentInstance(); System.out.println(price.format(12.31)); percent.setMinimumFractionDigits(2); System.out.println(percent.format(0.1231)); DateFormat date=DateFormat.getDateInstance(DateFormat.SHORT); System.out.println(date.format(new Date())); date=DateFormat.getDateTimeInstance( DateFormat.LONG,DateFormat.LONG); System.out.println(date.format(new Date())); } } Die Ausgabe ist 12,31 DM 12,31% 29.06.98 29. Juni 1998 11:46:10 GMT+02:00 Die Klasse Date behandelt ein Datum. Sie ist insbesondere von der aktuellen Zeitzone betroffen. Ein weiteres Gebiet für Internationalisierung ist die Ausgabe von Programmen in internationaler Form. Als Beispiel zeigen wir hier ein japanisches Java-Programm. 16 Ressourcen 16 - 10 Wie man sieht, sind alle Menütexte japanisch. Das gleiche sollte für Fehlermeldungen und Hilfetexte gelten. Um ein solches Programm zu erzeugen, sollte man die verwendeten Strings aus einer Ressource auslesen. Dazu verwendet man Property-Dateien, deren Namen aus einem String mit angehängtem Sprachraum und der Dateierweiterung .properties besteht. Ein Beispiel ist TestResource_de.properties. Java wählt diese Ressourcen-Datei automatisch aus, wenn man sich im deutschen Sprachraum befindet (oder Local.setDefault entsprechend eingestellt hat) und Ressourcen-Bündel verwendet. Dies geschieht am zweckmäßigsten in einer statischen Variable der Hauptklasse. Beispiel: public class Zirkel extends Applet { static ResourceBundle B; // verwendetes Bundle static String name (String tag, String def) // Finde Resourcenstring { String s; try { s=B.getString(tag); } catch (Exception e) { s=def; } return s; } public static void initBundle () // Initialisiere B 16 Ressourcen { 16 - 11 try { B=ResourceBundle.getBundle("zirkel"); } catch (Exception e) { B=null; } } public void init () // Zirkel wird als Applet aufgerufen { String s=getParameter("Language"); if (s!=null) Locale.setDefault(new Locale(s,"")); initBundle(); ... } public static void main (String args[]) // Zirkel wird als Applikation aufgerufen { if (args.length>=2) { if (args[0].startsWith("-l")) { Locale.setDefault(new Locale(args[1],"")); } } initBundle(); ... } } Nun kann jede Klasse mittels Zirkel.name(key,defaultvalue) den Wert der Ressource key auslesen. Das Programm kann übrigens als Applet oder als Applikation gestartet werden. Wir stellen uns vor, daß beide ein Fenster erzeugen, in dem das eigentliche Programm läuft. In Falle eines Applets läßt sich der Sprachraum mit einem Parameter einstellen. Im Falle des Aufrufs über main, läßt sich der Sprachraum über zwei Kommandozeilenparameter der Form -l lang setzen. Der String für den Sprachunterraum wird hier nicht verwendet. Serialization Unter Serialization versteht man die Fähigkeit von Objekten, sich in Strings umzuwandeln und umgekehrt. Diese Fähigkeit ist wichtig, wenn man bei sogenannten verteilten Anwendungen Objekte über das Netz weiterreichen will, beispielsweise dann, wenn man Methoden von Objekten aufruft, die sich auf einem anderen Rechner befinden und die Objekte als Parameter verwenden. In dieses Kapitel paßt Serialization deswegen hinein, weil sie ein einfach zu handhabendes Datenformat ergibt. Ein Objekt muß serialisierbar sein, um in einen String umgewandelt zu werden. Ein Objekt kann einfach dadurch, daß es das Interface Serializable implementiert, anzeigen, daß es serialisierbar ist. Es liegt allerdings in der Verantwortung des Objektes sicherzustellen, daß 16 Ressourcen 16 - 12 auch alle seine Variablen in Strings umgewandelt werden können. Für elementare Datentypen ist dies sicher der Fall. Außerdem ist es der Fall für Variablen, die sich auf serialisierbare Objekte oder Arrays von solchen Objekten beziehen. Einige vordefinierte Datentypen sind als serialisierbar deklariert. Als Beispiel erzeugen wir ein Objekt vom Typ Complex, speichern es auf eine Datei und laden das Objekt wieder von der Datei. import java.util.*; import java.io.*; class Complex implements Serializable // Eine einfache Klasse fuer komplexe Zahlen. { double Re,Im; public Complex (double re, double im) { Re=re; Im=im; } public double re () { return Re; } public double im () { return Im; } public String toString () // zum Ausdrucken { return Re+"+i*"+Im; } } public class Test { public static void main (String args[]) { Complex z=new Complex(2,1.1); System.out.println(z); try { // Object ausgeben: ObjectOutputStream out= new ObjectOutputStream( new FileOutputStream("test.dat")); out.writeObject(z); out.close(); // Object einlesen: ObjectInputStream in= new ObjectInputStream( new FileInputStream("test.dat")); Object o=in.readObject(); z=(Complex)o; in.close(); } catch (Exception e) { System.err.println(e); } System.out.println(z); } } Dies funktioniert auch, wenn man mehrere Objekte auf dieselbe Datei speichert. Man muß nur wissen, wieviele und von welchem Typ diese Objekte sind. Und es funktioniert für Arrays. public class Test { public static void main (String args[]) { // Erzeuge Array: Complex z[]={new Complex(2,1.1),new Complex(1,1)}; 16 Ressourcen 16 - 13 try { // Schreibe Array auf Datei: ObjectOutputStream out= new ObjectOutputStream(new FileOutputStream("test.dat")); out.writeObject(z); out.close(); // Lies Array ein: ObjectInputStream in= new ObjectInputStream(new FileInputStream("test.dat")); z=(Complex [])in.readObject(); in.close(); } catch (Exception e) { System.err.println(e); } // Drucke Array aus: for (int i=0; i<z.length; i++) System.out.println(z[i]); } } Falls das Objekt Referenzen auf serialisierbare Objekte enthält, werden diese automatisch mitgeschrieben. Dadurch läßt sich eine komplexere Datenstruktur, wie etwa eine Liste, abspeichern. Die Datei kann allerdings nur gelesen werden, wenn die zugehörigen Klassen bekannt sind und dieselbe Version haben. Bisweilen ändert sich jedoch an der Datenstruktur nichts, obwohl die Klasse neu übersetzt wurde. Man kann daher jeder serialisierbaren Klasse eine eigene Versionsnummer geben. Dies geschieht z.B. bei Complex folgendermaßen: class Complex implements Serializable { static final long serialVersionUID=100; ... } Nun werden alle Dateien, die dieselbe Versionsnummer enthalten, als kompatibel angesehen. Eine noch bessere Kontrolle erhält man durch eigene Schreibroutinen. Auf dieses Thema wollen wir hier nicht eingehen. Übungsaufgaben 1. Erweitern Sie die Klasse Help um die Fähigkeit, automatisch die lokale Hilfedatei aufzurufen. Dazu nehmen Sie an, daß die Hilfedatei z.B. topic_de_DE.txt heißt. Verwenden Sie Local.getDefault(). 2. Wie oft fiel der 13. eines Monats in diesem Jahrhundert (oder allgemeiner zwischen zwei Jahreszahlen, die in der Kommandozeile eingegeben werden können) auf die einzelnen Wochentage? Benutzen Sie dazu die Klasse GregorianCalendar und ihre Methode get(GregorianCalender.DAY_OF_WEEK). Geben Sie zunächst den aktuellen Wochentag aus, um das Ergebnis interpretieren zu können. 3. Nutzen Sie die Serialisierung, um einen Baum abzuspeichern. 16 Ressourcen 16 - 14 Lösungen. Aufgaben ohne Lösung 1. Testen Sie die Eingabe eines Datums mit der parse-Methode von DateFormat. 2. Packen Sie ein Applet in ein Archiv und starten Sie es mit dem Browser. 3. Packen Sie eine Hilfedatei dazu und zeigen Sie die Datei mit unserer HelpKlasse an.