Dateien als Ressourcen

Werbung
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ä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.
Herunterladen