From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- .../hjp5/html/k100263.html | 543 +++++++++++++++++++++ 1 file changed, 543 insertions(+) create mode 100644 Master/Reference Architectures and Patterns/hjp5/html/k100263.html (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100263.html') diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100263.html b/Master/Reference Architectures and Patterns/hjp5/html/k100263.html new file mode 100644 index 0000000..c26210d --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100263.html @@ -0,0 +1,543 @@ + + + +Handbuch der Java-Programmierung, 5. Auflage + + + + + + + + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage +
 <<  +  <   +  >   + >>  + API  +Kapitel 41 - Serialisierung +
+
+ + + + +

41.3 Anwendungen

+
+ +
+ + + + +

41.3.1 Ein einfacher Objektspeicher

+ +

+Die folgende Klasse TrivialObjectStore +stellt ein einfaches Beispiel für einen persistenten Objektspeicher +dar. Sie besitzt eine Methode putObject, +mit der beliebige String-Object-Paare +angelegt und später mit getObject +wieder abgerufen werden können. Durch Aufruf von save +kann der komplette Objektspeicher serialisiert werden, ein Aufruf +von load lädt ihn von der +Festplatte. Die Klasse TrivialObjectStore +verwendet eine Hashtable +zur Ablage der String-Object-Paare. +Diese implementiert bereits standardmäßig das Interface +Serializable +und kann daher sehr einfach auf einem externen Datenträger gespeichert +oder von dort geladen werden. + + +

+ + + + + +
+ +
+001 /* TrivialObjectStore.java */
+002 
+003 import java.io.*;
+004 import java.util.*;
+005 
+006 /**
+007  * Trivialer Objektspeicher, der Mengen von Name-Objekt-
+008  * Paaren aufnehmen und persistent speichern kann.
+009  */
+010 public class TrivialObjectStore
+011 {
+012   //Instance variables
+013   private String fname;
+014   private Hashtable objects;
+015 
+016   /**
+017    * Erzeugt einen neuen Objektspeicher mit dem angegebenen
+018    * Namen (die Erweiterung ".tos" ("trivial object store")
+019    * wird ggfs. automatisch angehängt.
+020    */
+021   public TrivialObjectStore(String fname)
+022   {
+023     this.fname = fname;
+024     if (!fname.endsWith(".tos")) {
+025       this.fname += ".tos";
+026     }
+027     this.objects = new Hashtable(50);
+028   }
+029 
+030   /**
+031    * Sichert den Objektspeicher unter dem im Konstruktor
+032    * angegebenen Namen.
+033    */
+034   public void save()
+035   throws IOException
+036   {
+037     FileOutputStream fs = new FileOutputStream(fname);
+038     ObjectOutputStream os = new ObjectOutputStream(fs);
+039     os.writeObject(objects);
+040     os.close();
+041   }
+042 
+043   /**
+044    * Lädt den Objektspeicher mit dem im Konstruktor
+045    * angegebenen Namen.
+046    */
+047   public void load()
+048   throws ClassNotFoundException, IOException
+049   {
+050     FileInputStream fs = new FileInputStream(fname);
+051     ObjectInputStream is = new ObjectInputStream(fs);
+052     objects = (Hashtable)is.readObject();
+053     is.close();
+054   }
+055 
+056   /**
+057    * Fügt ein Objekt in den Objektspeicher ein.
+058    */
+059   public void putObject(String name, Object object)
+060   {
+061     objects.put(name, object);
+062   }
+063 
+064   /**
+065    * Liest das Objekt mit dem angegebenen Namen aus dem
+066    * Objektspeicher. Ist es nicht vorhanden, wird null
+067    * zurückgegeben.
+068    */
+069   public Object getObject(String name)
+070   {
+071     return objects.get(name);
+072   }
+073 
+074   /**
+075    * Liefert eine Aufzählung aller gespeicherten Namen.
+076    */
+077   public Enumeration getAllNames()
+078   {
+079     return objects.keys();
+080   }
+081 }
+
+
+TrivialObjectStore.java
+ +Listing 41.9: Ein einfacher Objektspeicher

+ +

+Objekte der Klasse TrivialObjectStore +können nun verwendet werden, um beliebige serialisierbare Objekte +unter Zuordnung eines Namens auf einem externen Datenträger zu +speichern. Das folgende Listing zeigt dies am Beispiel eines fiktiven +»Tamagotchi-Shops«, dessen Eigenschaften Name, Besitzer +und Liste der Produkte im Objektspeicher abgelegt, in die Datei +shop.tos geschrieben und anschließend +wieder ausgelesen werden: + + +

+ + + + + +
+ +
+001 /* Listing4110.java */
+002 
+003 import java.io.*;
+004 import java.util.*;
+005 
+006 public class Listing4110
+007 {
+008   public static void main(String[] args)
+009   {
+010     //Erzeugen und Speichern des Objektspeichers
+011     TrivialObjectStore tos = new TrivialObjectStore("shop");
+012     tos.putObject("name", "Tami-Shop Norderelbe");
+013     tos.putObject("besitzer", "Meier, Fridolin");
+014     Vector products = new Vector(10);
+015     products.addElement("Dinky Dino");
+016     products.addElement("96er Classic");
+017     products.addElement("Black Frog");
+018     products.addElement("SmartGotchi");
+019     products.addElement("Pretty Dolly");
+020     tos.putObject("produkte", products);
+021     try {
+022       tos.save();
+023     } catch (IOException e) {
+024       System.err.println(e.toString());
+025     }
+026 
+027     //Einlesen des Objektspeichers 
+028     TrivialObjectStore tos2 = new TrivialObjectStore("shop");
+029     try {
+030       tos2.load();
+031       Enumeration names = tos2.getAllNames();
+032       while (names.hasMoreElements()) {
+033         String name = (String)names.nextElement();
+034         Object obj = tos2.getObject(name);
+035         System.out.print(name + ": ");
+036         System.out.println(obj.getClass().toString()); 
+037         if (obj instanceof Collection) {
+038           Iterator it = ((Collection)obj).iterator();
+039           while (it.hasNext()) {
+040             System.out.println("  " + it.next().toString());
+041           }
+042         } else {
+043           System.out.println("  " + obj.toString());
+044         }
+045       }
+046     } catch (IOException e) {
+047       System.err.println(e.toString());
+048     } catch (ClassNotFoundException e) {
+049       System.err.println(e.toString());
+050     }
+051   }
+052 }
+
+
+Listing4110.java
+ +Listing 41.10: Beispielanwendung für den einfachen Objektspeicher

+ +

+Hier wird zunächst ein neuer Objektspeicher tos +erstellt und mit den Objekten aus dem Tamagotchi-Shop gefüllt. +Neben zwei Strings name und +besitzer wird dabei unter der +Bezeichnung produkte eine weitere +Collection, der Vector +mit den Produkten, eingefügt. Das durch Aufruf von save +ausgelöste Serialisieren der Hashtable +bewirkt, dass alle darin gespeicherten Elemente serialisiert werden, +sofern sie das Interface Serializable +implementieren. + +

+Ab Zeile 027 wird +dann der Objektspeicher wieder eingelesen, in diesem Fall in die Variable +tos2. Mit getAllNames +beschafft das Programm zunächst eine Enumeration +über alle Objektnamen und durchläuft sie elementweise. Zu +jedem Namen wird mit getElement +das zugehörige Element geholt, und sein Name und der Name der +zugehörigen Klasse werden ausgegeben (Zeile 036). +Anschließend wird überprüft, ob das gefundene Objekt +das Interface Collection +implementiert und ggfs. über alle darin enthaltenen Elemente +iteriert. Andernfalls wird das Objekt direkt mit toString +ausgegeben. + +

+Die Ausgabe des Programms ist: + +

+produkte: class java.util.Vector
+  Dinky Dino
+  96er Classic
+  Black Frog
+  SmartGotchi
+  Pretty Dolly
+besitzer: class java.lang.String
+  Meier, Fridolin
+name: class java.lang.String
+  Tami-Shop Norderelbe
+
+ +

+ + + + + + + + + +
+ +

+Die Klasse TrivialObjectStore +verdeutlicht eine mögliche Vorgehensweise bei der persistenten +Speicherung von Objekten. Für einen echten Praxiseinsatz (etwa +in der Anwendungsentwicklung) fehlen aber noch ein paar wichtige Eigenschaften: +

    +
  • Anstatt den Objektspeicher immer komplett zu laden und +zu speichern, sollte es möglich sein, einzelne Elemente zu speichern, +zu laden und zu löschen. +
  • Der Objektspeicher sollte mehrbenutzerfähig sein und Transaktions- +und Recovery-Logik mitbringen. +
  • Die Suche nach Objekten sollte durch Indexdateien beschleunigt +werden können. +
+
+ + + + +
 Hinweis 
+
+ +

+Leider ist die Implementierung dieser Features nicht trivial. Ein +gutes Beispiel für die Implementierung des ersten und dritten +Punkts findet sich in »Java Algorithms« von Scott Robert +Ladd. Der Autor zeigt zunächst, wie man Objekte auf der Basis +von Random-Access-Dateien (anstelle der üblichen Streams) serialisiert. +Anschließend zeigt er die Verwendung von Indexdateien am Beispiel +der Implementierung von B-Trees. + + + + +

41.3.2 Kopieren von Objekten

+ +

+Eine auf den ersten Blick überraschende Anwendung der Serialisierung +besteht darin, Objekte zu kopieren. Es sei noch einmal daran erinnert, +dass die Zuweisung eines Objektes an eine Objektvariable lediglich +eine Zeigeroperation war; dass also immer nur ein Verweis geändert +wurde. Soll ein komplexes Objekt kopiert werden, wird dazu üblicherweise +das Interface Cloneable +implementiert und eine Methode clone +zur Verfügung gestellt, die den eigentlichen Kopiervorgang vornimmt. +Sollte ein Objekt kopiert werden, das Cloneable +nicht implementiert, blieb bisher nur der umständliche Weg über +das manuelle Kopieren aller Membervariablen. Das ist insbesondere +dann mühsam und fehlerträchtig, wenn das zu kopierende Objekt +Unterobjekte enthält, die ihrerseits kopiert werden müssen +(deep copy anstatt shallow copy). + +

+Der Schlüssel zum Kopieren von Objekten mit Hilfe der Serialisierung +liegt darin, anstelle der üblichen dateibasierten Streamklassen +solche zu verwenden, die ihre Daten im Hauptspeicher halten. Am besten +sind dazu ByteArrayOutputStream +und ByteArrayInputStream +geeignet. Sie sind integraler Bestandteil der OutputStream- +und InputStream-Hierarchien +und man kann die Daten problemlos von einem zum anderen übergeben. +Das folgende Programm implementiert eine Methode seriaClone(), +die ein beliebiges Objekt als Argument erwartet und in einen ByteArrayOutputStream +serialisiert. Das resultierende Byte-Array wird dann zur Konstruktion +eines ByteArrayInputStream +verwendet, dort deserialisiert und als Objektkopie an den Aufrufer +zurückgegeben: + + +

+ + + + + +
+ +
+001 /* Listing4111.java */
+002 
+003 import java.io.*;
+004 import java.util.*;
+005 
+006 public class Listing4111
+007 {
+008   public static Object seriaClone(Object o)
+009   throws IOException, ClassNotFoundException
+010   {
+011     //Serialisieren des Objekts
+012     ByteArrayOutputStream out = new ByteArrayOutputStream();
+013     ObjectOutputStream os = new ObjectOutputStream(out);
+014     os.writeObject(o);
+015     os.flush();
+016     //Deserialisieren des Objekts
+017     ByteArrayInputStream in = new ByteArrayInputStream(
+018       out.toByteArray()
+019     );
+020     ObjectInputStream is = new ObjectInputStream(in);
+021     Object ret = is.readObject();
+022     is.close();
+023     os.close();
+024     return ret;
+025   }
+026 
+027   public static void main(String[] args)
+028   {
+029     try {
+030       //Erzeugen des Buchobjekts
+031       Book book = new Book();
+032       book.author = "Peitgen, Heinz-Otto";
+033       String[] s = {"Jürgens, Hartmut", "Saupe, Dietmar"};
+034       book.coAuthors = s;
+035       book.title = "Bausteine des Chaos";
+036       book.publisher = "rororo science";
+037       book.pubyear = 1998;
+038       book.pages = 514;
+039       book.isbn = "3-499-60250-4";
+040       book.reflist = new Vector();
+041       book.reflist.addElement("The World of MC Escher");
+042       book.reflist.addElement(
+043         "Die fraktale Geometrie der Natur"
+044       );
+045       book.reflist.addElement("Gödel, Escher, Bach");
+046       System.out.println(book.toString());
+047       //Erzeugen und Verändern der Kopie
+048       Book copy = (Book)seriaClone(book);
+049       copy.title += " - Fraktale";
+050       copy.reflist.addElement("Fractal Creations");
+051       //Ausgeben von Original und Kopie
+052       System.out.print(book.toString());
+053       System.out.println("---");
+054       System.out.print(copy.toString());
+055     } catch (IOException e) {
+056       System.err.println(e.toString());
+057     } catch (ClassNotFoundException e) {
+058       System.err.println(e.toString());
+059     }
+060   }
+061 }
+062 
+063 class Book
+064 implements Serializable
+065 {
+066   public String author;
+067   public String[] coAuthors;
+068   public String title;
+069   public String publisher;
+070   public int    pubyear;
+071   public int    pages;
+072   public String isbn;
+073   public Vector reflist;
+074 
+075   public String toString()
+076   {
+077     String NL = System.getProperty("line.separator");
+078     StringBuffer ret = new StringBuffer(200);
+079     ret.append(author + NL);
+080     for (int i = 0; i < coAuthors.length; ++i) {
+081       ret.append(coAuthors[i] + NL);
+082     }
+083     ret.append("\"" + title + "\"" + NL);
+084     ret.append(publisher + " " + pubyear + NL);
+085     ret.append(pages + " pages" + NL);
+086     ret.append(isbn + NL);
+087     Enumeration e = reflist.elements();
+088     while (e.hasMoreElements()) {
+089       ret.append("  " + (String)e.nextElement() + NL);
+090     }
+091     return ret.toString();
+092   }
+093 }
+
+
+Listing4111.java
+ +Listing 41.11: Kopieren von Objekten durch Serialisierung

+ +

+Das Programm verwendet zum Testen ein Objekt der Klasse Book, +das mit den Daten eines Buchtitels initialisiert wird. Anschließend +wird mit seriaClone eine Kopie +hergestellt und der Variable copy +zugewiesen. Um zu verdeutlichen, dass wirklich eine Kopie hergestellt +wurde, modifizieren wir nun einige Angaben der Kopie und geben anschließend +beide Objekte aus: + +

+Peitgen, Heinz-Otto
+Jürgens, Hartmut
+Saupe, Dietmar
+"Bausteine des Chaos"
+rororo science 1998
+514 pages
+3-499-60250-4
+  The World of MC Escher
+  Die fraktale Geometrie der Natur
+  Gödel, Escher, Bach
+---
+Peitgen, Heinz-Otto
+Jürgens, Hartmut
+Saupe, Dietmar
+"Bausteine des Chaos - Fraktale"
+rororo science 1998
+514 pages
+3-499-60250-4
+  The World of MC Escher
+  Die fraktale Geometrie der Natur
+  Gödel, Escher, Bach
+  Fractal Creations
+
+ + +

+An der Programmausgabe kann man erkennen, dass das Objekt tatsächlich +ordnungsgemäß kopiert wurde. Auch alle Unterobjekte wurden +kopiert und konnten anschließend unabhängig voneinander +geändert werden. Ohne Serialisierung wäre der manuelle Aufwand +um ein Vielfaches größer gewesen. Das Verfahren findet +dort seine Grenzen, wo die zu kopierenden Objekte nicht serialisierbar +sind oder nicht-serialisierbare Unterobjekte enthalten. Zudem muss +im echten Einsatz das Laufzeitverhalten überprüft werden, +denn der Vorgang des Serialisierens/Deserialisierens ist um ein Vielfaches +langsamer als das direkte Kopieren der Objektattribute. +


+ + + +
 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 +
+ + + -- cgit v1.2.3