1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
|
<html>
<head>
<title>
Handbuch der Java-Programmierung, 5. Auflage
</title>
</head>
<body>
<a name="startofbody"></a>
<script language="JavaScript" src="hjp4lib.js">
</script>
<script language="JavaScript">
installKbdHandler("97,#startofbody;101,#endofbody;116,cover.html;122,k100003.html;115,search.html;105,index.html;100,JDKDOCS;112,APIDOCS;104,k100260.html;106,k100261.html;107,k100263.html;108,k100265.html");
</script>
<table border=0 cellpadding=0 cellspacing=1 width="100%">
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="cover.html"> Titel </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100003.html"> Inhalt </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="search.html"> Suchen </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="index.html"> Index </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/index.html" onClick="this.href=getDocIndex()"> DOC </a>
<td align="right">Handbuch der Java-Programmierung, 5. Auflage
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100260.html"> << </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100261.html"> < </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100263.html"> > </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100265.html"> >> </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/api/index.html" onClick="this.href=getApiIndex()"> API </a>
<td align="right">Kapitel 41 - Serialisierung
</table>
<hr>
<!-- Section -->
<a name="sectlevel2id041002"></a>
<h2>41.2 Weitere Aspekte der Serialisierung </h2>
<hr>
<ul>
<li><a href="k100262.html#sectlevel2id041002">41.2 Weitere Aspekte der Serialisierung</a>
<ul>
<li><a href="k100262.html#versionierung">41.2.1 Versionierung</a>
<li><a href="k100262.html#sectlevel3id041002002">41.2.2 Nicht-serialisierte Membervariablen</a>
<li><a href="k100262.html#objektreferenzen">41.2.3 Objektreferenzen</a>
<li><a href="k100262.html#sectlevel3id041002004">41.2.4 Serialisieren von Collections</a>
</ul>
</ul>
<hr>
<p>
Mit den Grundlagen aus dem vorigen Abschnitt sind bereits die wichtigsten
Prinzipien der Serialisierung in Java erklärt. Beeindruckend
ist dabei einerseits, wie das Konzept in die Klassenbibliothek eingebunden
wurde. <a href="index_o.html#ixb101007"><font color=#000080><tt>ObjectOutputStream</tt></font></a>
und <a href="index_o.html#ixb101038"><font color=#000080><tt>ObjectInputStream</tt></font></a>
passen in natürlicher Weise in die Stream-Hierarchie und zeigen,
wie man Streams konstruiert, die <i>strukturierte</i> Daten verarbeiten.
Andererseits ist es eine große Hilfe, dass Objekte ohne größere
Änderungen serialisiert werden können. Es ist lediglich
erforderlich, das <a href="index_s.html#ixb100454"><font color=#000080><tt>Serializable</tt></font></a>-Interface
zu implementieren, um ein einfaches Objekt persistent machen zu können.
<p>
Dennoch ist das API leistungsfähig genug, auch komplexe Klassen
serialisierbar zu machen. Wir wollen in diesem Abschnitt weiterführende
Aspekte betrachten, die im Rahmen dieser Einführung noch verständlich
sind. Daneben gibt es weitere Möglichkeiten, mit denen das Serialisieren
und Deserialisieren von Klassen komplett an die speziellen Anforderungen
einer Applikation angepasst werden kann. Auf diese Details wollen
wir hier aber nicht eingehen. Als vertiefende Lektüre empfiehlt
sich die »Java Object Serialization Specification«, die
seit der Version 1.2 Bestandteil der Online-Dokumentation des JDK
ist.
<!-- Section -->
<a name="versionierung"></a>
<h3>41.2.1 Versionierung </h3>
<p>
Applikationen, in denen Code und Daten getrennt gehalten werden, haben
grundsätzlich mit dem Problem der Inkonsistenz beider Bestandteile
zu kämpfen. Wie kann sichergestellt werden, dass die Struktur
der zu verarbeitenden Daten tatsächlich den vom Programm erwarteten
Strukturen entspricht? Dieses Problem gibt es bei praktisch allen
Datenbankanwendungen, und es tritt immer dann verstärkt auf,
wenn Code und Datenstruktur getrennt geändert werden. Auch durch
das Serialisieren von Objekten haben wir das Problem, denn die Datei
mit den serialisierten Objekten enthält nur die <i>Daten</i>,
der zugehörige <i>Code</i> kommt dagegen aus dem <font color="#660099">.class</font>-File.
<p>
Das Serialisierungs-API versucht diesem Problem mit einem <a name="ixa103018"><i>Versionierungsmechanismus</i></a>
zu begegnen. Dazu enthält das Interface <a href="index_s.html#ixb100454"><font color=#000080><tt>Serializable</tt></font></a>
eine <a href="index_l.html#ixb100245"><font color=#000080><tt>long</tt></font></a>-Konstante
<a name="ixa103019"><a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a></a>,
in der eine Versionskennung zur Klasse gespeichert wird. Sie wird
beim Aufruf von <a href="index_w.html#ixb102213"><font color=#000080><tt>writeObject</tt></font></a>
automatisch berechnet und stellt einen Hashcode über die wichtigsten
Eigenschaften der Klasse dar. So gehen beispielsweise Name und Signatur
der Klasse, implementierte Interfaces sowie Methoden und Konstruktoren
in die Berechnung ein. Selbst triviale Änderungen wie das Umbenennen
oder Hinzufügen einer öffentlichen Methode verändern
die <a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a>.
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100%>
<tr>
<td width=1 align=left valign=top bgcolor="#0099CC"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=1></td>
<td width=1 align=left valign=top bgcolor="#0099CC"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top width=1000>
<p>
Die <a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a>
einer Klasse kann mit Hilfe des Hilfsprogramms <a name="ixa103020"><a href="index_s.html#ixb102218"><font color=#000080><tt>serialver</tt></font></a></a>
ermittelt werden. Dieses einfache Programm wird zusammen mit dem Namen
der Klasse in der Kommandozeile aufgerufen und liefert die Versionsnummer
als Ausgabe. Alternativ kann es auch mit dem Argument <font color="#000077"><tt>-show</tt></font>
aufgerufen werden. Es hat dann eine einfache Oberfläche, in der
der Name der Klasse interaktiv eingegeben werden kann (siehe <a href="k100262.html#serialver">Abbildung 41.1</a>).</td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top>
<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#0099CC">
<tr>
<td><font color="#FFFFFF"> Tipp </font></td>
</tr>
</table>
</td>
<td width=1 align=left valign=top bgcolor="#0099CC"><img src="trp1_1.gif"></td>
</tr>
</table>
<p>
<a name="serialver"></a>
<img src="images/SerialVer.gif">
<p>
<p><i>
Abbildung 41.1: Das Programm serialver</i></p>
<p>
Beim Serialisieren eines Objektes wird auch die <a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a>
der zugehörigen Klasse mit in die Ausgabedatei geschrieben. Soll
das Objekt später deserialisiert werden, so wird die in der Datei
gespeicherte <a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a>
mit der aktuellen <a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a>
des geladenen <font color="#660099">.class</font>-Files verglichen.
Stimmen beide nicht überein, so gibt es eine Ausnahme des Typs
<a name="ixa103021"><a href="index_i.html#ixb102219"><font color=#000080><tt>InvalidClassException</tt></font></a></a>,
und der Deserialisierungsvorgang bricht ab.
<p>
Diese Art der Versionierung ist zwar recht sicher, aber auch sehr
rigoros. Schon eine kleine Änderung an der Klasse macht die serialisierten
Objekte unbrauchbar, weil sie sich nicht mehr deserialisieren lassen.
Die in <a href="k100261.html#timelisting">Listing 41.1</a> vorgestellte
Klasse <font color="#000077"><tt>Time</tt></font> hat die <a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a>
<font color="#000077"><tt>-8717671986526504937L</tt></font>. Wird
beispielsweise eine neue Methode <font color="#000077"><tt>public
void test()</tt></font> hinzugefügt (die für das Deserialisieren
eigentlich völlig bedeutungslos ist), ändert sich die <a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a>
auf <font color="#000077"><tt>9202005869290334574L</tt></font>, und
weder die Datei <font color="#660099">test1.ser</font> noch <font color="#660099">test2.ser</font>
lassen sich zukünftig deserialisieren.
<p>
Anstatt die <a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a>
automatisch berechnen zu lassen, kann sie von der zu serialisierenden
Klasse auch fest vorgegeben werden. Dazu wird einfach eine Konstante
<font color="#000077"><tt>static final long serialVersionUID</tt></font>
definiert und mit einem vorgegebenen Wert belegt (der zum Beispiel
mit Hilfe von <a href="index_s.html#ixb102218"><font color=#000080><tt>serialver</tt></font></a>
ermittelt wird). In diesem Fall wird die <a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a>
beim Aufruf von <a href="index_w.html#ixb102213"><font color=#000080><tt>writeObject</tt></font></a>
nicht neu berechnet, sondern es wird der vorgegebene Wert verwendet.
Läßt man diese Konstante unverändert, können
beliebige Änderungen der Klasse durchgeführt werden, ohne
dass <a href="index_r.html#ixb102215"><font color=#000080><tt>readObject</tt></font></a>
beim Deserialisieren mit einer Ausnahme abbricht. Die <font color="#000077"><tt>Time</tt></font>-Klasse
aus <a href="k100261.html#timelisting">Listing 41.1</a> hätte
dann folgendes Aussehen:
<a name="listingid041006"></a>
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
<tr>
<td valign=top>
<font color="#000055">
<pre>
<font color="#555555">001 </font><font color="#0000AA">import</font> java.io.*;
<font color="#555555">002 </font>
<font color="#555555">003 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Time
<font color="#555555">004 </font><font color="#0000AA">implements</font> Serializable
<font color="#555555">005 </font>{
<font color="#555555">006 </font> <font color="#0000AA">static</font> <font color="#0000AA">final</font> <font color="#006699">long</font> serialVersionUID = -8717671986526504937L;
<font color="#555555">007 </font>
<font color="#555555">008 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> hour;
<font color="#555555">009 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> minute;
<font color="#555555">010 </font>
<font color="#555555">011 </font> <font color="#0000AA">public</font> Time(<font color="#006699">int</font> hour, <font color="#006699">int</font> minute)
<font color="#555555">012 </font> {
<font color="#555555">013 </font> <font color="#006699">this</font>.hour = hour;
<font color="#555555">014 </font> <font color="#006699">this</font>.minute = minute;
<font color="#555555">015 </font> }
<font color="#555555">016 </font>
<font color="#555555">017 </font> <font color="#0000AA">public</font> String toString()
<font color="#555555">018 </font> {
<font color="#555555">019 </font> <font color="#0000AA">return</font> hour + <font color="#0000FF">":"</font> + minute;
<font color="#555555">020 </font> }
<font color="#555555">021 </font>}</pre>
</font>
</td>
</tr>
</table>
<i>
Listing 41.6: Die Uhrzeitklasse mit serialVersionUID</i></p>
<p>
Jetzt muss die Anwendung natürlich selbst darauf achten, dass
die durchgeführten Änderungen kompatibel sind, dass also
durch das Laden der Daten aus dem älteren Objekt keine Inkonsistenzen
verursacht werden. Dabei mögen folgende Regeln als Anhaltspunkte
dienen:
<ul>
<li>Das Hinzufügen oder Entfernen von Methoden ist meist unkritisch.
<li>Das Entfernen von Membervariablen ist meist unkritisch.
<li>Beim Hinzufügen neuer Membervariablen muss beachtet werden,
dass diese nach dem Deserialisieren uninitialisiert sind.
<li>Problematisch ist es meist, Membervariablen umzubenennen, sie
auf <a href="index_t.html#ixb100429"><font color=#000080><tt>transient</tt></font></a>
oder <a href="index_s.html#ixb100422"><font color=#000080><tt>static</tt></font></a>
(oder umgekehrt) zu ändern, die Klasse von <a href="index_s.html#ixb100454"><font color=#000080><tt>Serializable</tt></font></a>
auf <a name="ixa103022"><a href="index_e.html#ixb102220"><font color=#000080><tt>Externalizable</tt></font></a></a>
(oder umgekehrt) zu ändern oder den Klassennamen zu ändern.
</ul>
<p>
Solange die Änderungen kompatibel bleiben, ist also durch eine
feste <a href="index_s.html#ixb102217"><font color=#000080><tt>serialVersionUID</tt></font></a>
sichergestellt, dass serialisierte Objekte lesbar und deserialisierbar
bleiben. Sind die Änderungen dagegen inkompatibel, sollte die
Konstante entsprechend geändert werden, und die serialisierten
Daten dürfen nicht mehr verwendet werden (bzw. müssen vor
der weiteren Verwendung konvertiert werden).
<!-- Section -->
<a name="sectlevel3id041002002"></a>
<h3>41.2.2 Nicht-serialisierte Membervariablen </h3>
<p>
Mitunter besitzt eine Klasse Membervariablen, die nicht serialisiert
werden sollen. Typische Beispiele sind Variablen, deren Wert sich
während des Programmlaufs dynamisch ergibt, oder solche, die
nur der temporären Kommunikation zwischen zwei oder mehr Methoden
dienen. Auch Daten, die nur im Kontext der laufenden Anwendung Sinn
machen, wie beispielsweise Filehandles, Sockets, GUI-Ressourcen oder
JDBC-Verbindungen, sollten nicht serialisiert werden; sie »verfallen«
mit dem Ende des Programms.
<p>
Membervariablen, die nicht serialisiert werden sollen, können
mit dem Attribut <a name="ixa103023"><a href="index_t.html#ixb100429"><font color=#000080><tt>transient</tt></font></a></a>
versehen werden. Dadurch werden sie beim Schreiben des Objekts mit
<a href="index_w.html#ixb102213"><font color=#000080><tt>writeObject</tt></font></a>
ignoriert und gelangen nicht in die Ausgabedatei. Beim Deserialisieren
werden die transienten Objekte lediglich mit dem typspezifischen Standardwert
belegt.
<!-- Section -->
<a name="objektreferenzen"></a>
<h3>41.2.3 Objektreferenzen </h3>
<p>
Eine wichtige Eigenschaft des Serialisierungs-APIs im JDK ist die,
dass auch <i>Referenzen</i> automatisch gesichert und rekonstruiert
werden. Besitzt ein Objekt selbst Strings, Arrays oder andere Objekte
als Membervariablen, so werden diese ebenso wie die primitiven Typen
serialisiert und deserialisiert. Da eine Objektvariable lediglich
einen <i>Verweis</i> auf das im Hauptspeicher allozierte Objekt darstellt,
ist es wichtig, dass diese Verweise auch nach dem Serialisieren/Deserialisieren
erhalten bleiben. Insbesondere darf ein Objekt auch dann nur einmal
angelegt werden, wenn darauf von mehr als einer Variable verwiesen
wird. Auch nach dem Deserialisieren darf das Objekt nur einmal vorhanden
sein, und die verschiedenen Objektvariablen müssen auf dieses
Objekt zeigen.
<p>
Der <a href="index_o.html#ixb101007"><font color=#000080><tt>ObjectOutputStream</tt></font></a>
hält zu diesem Zweck eine Hashtabelle, in der alle bereits serialisierten
Objekte verzeichnet werden. Bei jedem Aufruf von <a href="index_w.html#ixb102213"><font color=#000080><tt>writeObject</tt></font></a>
wird zunächst in der Tabelle nachgesehen, ob das Objekt bereits
serialisiert wurde. Ist das der Fall, wird in der Ausgabedatei lediglich
ein Verweis auf das Objekt gespeichert. Andernfalls wird das Objekt
serialisiert und in der Hashtabelle eingetragen. Beim Deserialisieren
eines Verweises wird dieser durch einen Objektverweis auf das zuvor
deserialisierte Objekt ersetzt. Auf diese Weise werden Objekte nur
einmal gespeichert, die Objektreferenzen werden konserviert, und das
Problem von Endlosschleifen durch zyklische Referenzen ist ebenfalls
gelöst.
<p>
Das folgende Programm zeigt das Speichern von Verweisen am Beispiel
eines Graphen, der Eltern-Kind-Beziehungen darstellt. Zunächst
benötigen wir dazu eine Klasse <font color="#000077"><tt>Person</tt></font>,
die den Namen und die Eltern einer Person speichern kann. Jeder Elternteil
wird dabei durch einen Verweis auf eine weitere Person dargestellt:
<a name="listingid041007"></a>
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
<tr>
<td valign=top>
<font color="#000055">
<pre>
<font color="#555555">001 </font><font color="#0000AA">import</font> java.io.*;
<font color="#555555">002 </font>
<font color="#555555">003 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Person
<font color="#555555">004 </font><font color="#0000AA">implements</font> Serializable
<font color="#555555">005 </font>{
<font color="#555555">006 </font> <font color="#0000AA">public</font> String name;
<font color="#555555">007 </font> <font color="#0000AA">public</font> Person mother;
<font color="#555555">008 </font> <font color="#0000AA">public</font> Person father;
<font color="#555555">009 </font>
<font color="#555555">010 </font> <font color="#0000AA">public</font> Person(String name)
<font color="#555555">011 </font> {
<font color="#555555">012 </font> <font color="#006699">this</font>.name = name;
<font color="#555555">013 </font> }
<font color="#555555">014 </font>}</pre>
</font>
</td>
<td valign=top align=right>
<a href="../examples/Person.java"><font color="#000055" size=-1>Person.java</font></a></td>
</tr>
</table>
<i>
Listing 41.7: Die Klasse Person</i></p>
<p>
Der Einfachheit halber wurden alle Membervariablen als <a href="index_p.html#ixb100084"><font color=#000080><tt>public</tt></font></a>
deklariert. Wir wollen nun ein Programm erstellen, das den folgenden
Eltern-Kind-Graph aufbaut:
<p>
<a name="elternkindgraph"></a>
<img src="images/ElternKindSeri.gif">
<p>
<p><i>
Abbildung 41.2: Eltern-Kind-Graph für Serialisierungsbeispiel</i></p>
<p>
Das Programm soll den Graph dann in eine Datei <font color="#660099">test3.ser</font>
serialisieren und anschließend durch Deserialisieren wieder
rekonstruieren. Wir wollen dann überprüfen, ob alle Verweise
wiederhergestellt wurden und ob die Objekteindeutigkeit gewahrt wurde.
<a name="seriref"></a>
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
<tr>
<td valign=top>
<font color="#000055">
<pre>
<font color="#555555">001 </font><font color="#00AA00">/* Listing4108.java */</font>
<font color="#555555">002 </font>
<font color="#555555">003 </font><font color="#0000AA">import</font> java.io.*;
<font color="#555555">004 </font><font color="#0000AA">import</font> java.util.*;
<font color="#555555">005 </font>
<font color="#555555">006 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Listing4108
<font color="#555555">007 </font>{
<font color="#555555">008 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
<font color="#555555">009 </font> {
<font color="#555555">010 </font> <font color="#00AA00">//Erzeugen der Familie</font>
<font color="#555555">011 </font> Person opa = <font color="#0000AA">new</font> Person(<font color="#0000FF">"Eugen"</font>); <a name="seriref.a"></a>
<font color="#555555">012 </font> Person oma = <font color="#0000AA">new</font> Person(<font color="#0000FF">"Therese"</font>);
<font color="#555555">013 </font> Person vater = <font color="#0000AA">new</font> Person(<font color="#0000FF">"Barny"</font>);
<font color="#555555">014 </font> Person mutter = <font color="#0000AA">new</font> Person(<font color="#0000FF">"Wilma"</font>);
<font color="#555555">015 </font> Person kind1 = <font color="#0000AA">new</font> Person(<font color="#0000FF">"Fritzchen"</font>);
<font color="#555555">016 </font> Person kind2 = <font color="#0000AA">new</font> Person(<font color="#0000FF">"Kalli"</font>);
<font color="#555555">017 </font> vater.father = opa;
<font color="#555555">018 </font> vater.mother = oma;
<font color="#555555">019 </font> kind1.father = kind2.father = vater;
<font color="#555555">020 </font> kind1.mother = kind2.mother = mutter; <a name="seriref.b"></a>
<font color="#555555">021 </font>
<font color="#555555">022 </font> <font color="#00AA00">//Serialisieren der Familie</font>
<font color="#555555">023 </font> <font color="#0000AA">try</font> {
<font color="#555555">024 </font> FileOutputStream fs = <font color="#0000AA">new</font> FileOutputStream(<font color="#0000FF">"test3.ser"</font>);
<font color="#555555">025 </font> ObjectOutputStream os = <font color="#0000AA">new</font> ObjectOutputStream(fs);
<font color="#555555">026 </font> os.writeObject(kind1);
<font color="#555555">027 </font> os.writeObject(kind2);
<font color="#555555">028 </font> os.close();
<font color="#555555">029 </font> } <font color="#0000AA">catch</font> (IOException e) {
<font color="#555555">030 </font> System.err.println(e.toString());
<font color="#555555">031 </font> }
<font color="#555555">032 </font>
<font color="#555555">033 </font> <font color="#00AA00">//Rekonstruieren der Familie</font>
<font color="#555555">034 </font> kind1 = kind2 = <font color="#006699">null</font>; <a name="seriref.c"></a>
<font color="#555555">035 </font> <font color="#0000AA">try</font> {
<font color="#555555">036 </font> FileInputStream fs = <font color="#0000AA">new</font> FileInputStream(<font color="#0000FF">"test3.ser"</font>);
<font color="#555555">037 </font> ObjectInputStream is = <font color="#0000AA">new</font> ObjectInputStream(fs);
<font color="#555555">038 </font> kind1 = (Person)is.readObject();
<font color="#555555">039 </font> kind2 = (Person)is.readObject();
<font color="#555555">040 </font> <font color="#00AA00">//Überprüfen der Objekte</font>
<font color="#555555">041 </font> System.out.println(kind1.name); <a name="seriref.d"></a>
<font color="#555555">042 </font> System.out.println(kind2.name);
<font color="#555555">043 </font> System.out.println(kind1.father.name);
<font color="#555555">044 </font> System.out.println(kind1.mother.name);
<font color="#555555">045 </font> System.out.println(kind2.father.name);
<font color="#555555">046 </font> System.out.println(kind2.mother.name);
<font color="#555555">047 </font> System.out.println(kind1.father.father.name);
<font color="#555555">048 </font> System.out.println(kind1.father.mother.name); <a name="seriref.e"></a>
<font color="#555555">049 </font> <font color="#00AA00">//Name des Vaters ändern</font>
<font color="#555555">050 </font> kind1.father.name = <font color="#0000FF">"Fred"</font>; <a name="seriref.f"></a>
<font color="#555555">051 </font> <font color="#00AA00">//Erneutes Überprüfen der Objekte</font>
<font color="#555555">052 </font> System.out.println(<font color="#0000FF">"---"</font>); <a name="seriref.g"></a>
<font color="#555555">053 </font> System.out.println(kind1.name);
<font color="#555555">054 </font> System.out.println(kind2.name);
<font color="#555555">055 </font> System.out.println(kind1.father.name);
<font color="#555555">056 </font> System.out.println(kind1.mother.name);
<font color="#555555">057 </font> System.out.println(kind2.father.name);
<font color="#555555">058 </font> System.out.println(kind2.mother.name);
<font color="#555555">059 </font> System.out.println(kind1.father.father.name);
<font color="#555555">060 </font> System.out.println(kind1.father.mother.name); <a name="seriref.h"></a>
<font color="#555555">061 </font> is.close();
<font color="#555555">062 </font> } <font color="#0000AA">catch</font> (ClassNotFoundException e) {
<font color="#555555">063 </font> System.err.println(e.toString());
<font color="#555555">064 </font> } <font color="#0000AA">catch</font> (IOException e) {
<font color="#555555">065 </font> System.err.println(e.toString());
<font color="#555555">066 </font> }
<font color="#555555">067 </font> }
<font color="#555555">068 </font>}</pre>
</font>
</td>
<td valign=top align=right>
<a href="../examples/Listing4108.java"><font color="#000055" size=-1>Listing4108.java</font></a></td>
</tr>
</table>
<i>
Listing 41.8: Serialisieren von Objekten und Referenzen</i></p>
<p>
Das Programm erzeugt in den Zeilen <a href="k100262.html#seriref.a">011</a>
bis <a href="k100262.html#seriref.b">020</a> zunächst den in
<a href="k100262.html#elternkindgraph">Abbildung 41.2</a> abgebildeten
Verwandtschaftsgraph und serialisiert ihn anschließend in die
Datei <font color="#660099">test3.ser</font>. Bemerkenswert ist hier
vor allem, dass wir lediglich die beiden Kinder <font color="#000077"><tt>kind1</tt></font>
und <font color="#000077"><tt>kind2</tt></font> explizit serialisieren.
Da alle anderen Objekte über Verweise von den Kindern aus zu
erreichen sind, ist es nicht nötig, diese separat mit <a href="index_w.html#ixb102213"><font color=#000080><tt>writeObject</tt></font></a>
zu speichern.
<p>
In <a href="k100262.html#seriref.c">Zeile 034</a> setzen wir die beiden
Kindvariablen auf <a href="index_n.html#ixb100235"><font color=#000080><tt>null</tt></font></a>,
um zu beweisen, dass sie ausschließlich durch das nachfolgende
Deserialisieren korrekt gesetzt werden. Nun werden <font color="#000077"><tt>kind1</tt></font>
und <font color="#000077"><tt>kind2</tt></font> deserialisiert, und
in den Zeilen <a href="k100262.html#seriref.d">041</a> bis <a href="k100262.html#seriref.e">048</a>
wird der komplette Verwandtschaftsgraph ausgegeben. An der Ausgabe
des Programms können wir erkennen, dass tatsächlich alle
Objekte rekonstruiert und die Verweise darauf korrekt gesetzt wurden:
<font color="#333300">
<pre>
Fritzchen
Kalli
Barny
Wilma
Barny
Wilma
Eugen
Therese
---
Fritzchen
Kalli
Fred
Wilma
Fred
Wilma
Eugen
Therese
</pre>
</font>
<p>
Der zweite Block von Ausgabeanweisungen (in den Zeilen <a href="k100262.html#seriref.g">052</a>
bis <a href="k100262.html#seriref.h">060</a>) zeigt, dass auch die
Objekteindeutigkeit gewahrt wurde. Dazu haben wir nämlich in
<a href="k100262.html#seriref.f">Zeile 050</a> den Namen des Vaterobjekts
von <font color="#000077"><tt>kind1</tt></font> auf »Fred«
geändert. Wie im zweiten Teil der Ausgabe des Programms zu erkennen
ist, wurde damit auch der Name des Vaters des zweiten Kindes auf »Fred«
geändert, und wir können sicher sein, dass es sich um ein
und dasselbe Objekt handelt.
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100%>
<tr>
<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=1></td>
<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top width=1000>
<p>
Obwohl (oder gerade weil) das Serialisieren von Objektgraphen in aller
Regel sehr bequem und vollautomatisch abläuft, seien an dieser
Stelle einige Warnungen ausgesprochen:
<ul>
<li>Einerseits kann es passieren, dass mehr Objekte als erwartet serialisiert
werden. Insbesondere bei komplexen Objektbeziehungen kann es sein,
dass an dem zu serialisierenden Objekt indirekt viele weitere Objekte
hängen und beim Serialisieren wesentlich mehr Objekte gespeichert
werden, als erwartet wurde. Das kostet unnötig Zeit und Speicher.
<li>Durch das Zwischenspeichern der bereits serialisierten Objekte
in <a href="index_o.html#ixb101007"><font color=#000080><tt>ObjectOutputStream</tt></font></a>
werden viele Verweise auf Objekte gehalten, die sonst möglicherweise
für das Programm unerreichbar wären. Da der Garbage Collector
diese Objekte nicht freigibt, kann es beim Serialisieren einer großen
Anzahl von Objekten zu Speicherproblemen kommen. Mit Hilfe der Methode
<a name="ixa103024"><a href="index_r.html#ixb100977"><font color=#000080><tt>reset</tt></font></a></a>
kann der <a href="index_o.html#ixb101007"><font color=#000080><tt>ObjectOutputStream</tt></font></a>
in den Anfangszustand versetzt werden; alle bereits bekannten Objektreferenzen
werden »vergessen«. Wird ein bereits serialisiertes Objekt
danach noch einmal gespeichert, wird kein Verweis, sondern das Objekt
selbst noch einmal geschrieben.
<li>Wenn ein bereits serialisiertes Objekt <i>verändert</i> und
anschließend erneut serialisiert wird, bleibt die Veränderung
beim Deserialisieren unsichtbar, denn in der Ausgabedatei wird lediglich
ein Verweis auf das Originalobjekt gespeichert.
</ul>
</td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top>
<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#CC0000">
<tr>
<td><font color="#FFFFFF"> Warnung </font></td>
</tr>
</table>
</td>
<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
</tr>
</table>
<!-- Section -->
<a name="sectlevel3id041002004"></a>
<h3>41.2.4 Serialisieren von Collections </h3>
<p>
Neben selbstgeschriebenen Klassen sind auch viele der Standardklassen
des JDK serialisierbar, insbesondere die meisten Collection-Klassen.
Um beispielsweise alle Daten eines Vektors oder einer Hashtable persistent
zu speichern, genügt ein einfaches Serialisieren nach obigem
Muster. Voraussetzung ist allerdings, dass auch die Elemente der Collection
serialisierbar sind, andernfalls gibt es eine <a name="ixa103025"><a href="index_n.html#ixb102214"><font color=#000080><tt>NotSerializableException</tt></font></a></a>.
Auch die Wrapperklassen zu den Basistypen (siehe <a href="k100066.html#wrapperklassen">Abschnitt 10.2</a>)
sind standardmäßig serialisierbar und können damit
problemlos als Objekte in serialisierbaren Collections verwendet werden.
Im nächsten Abschnitt stellen wir eine kleine Anwendung für
das Serialisieren von Hashtabellen vor.
<hr>
<table border=0 cellpadding=0 cellspacing=1 width="100%">
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="cover.html"> Titel </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100003.html"> Inhalt </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="search.html"> Suchen </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="index.html"> Index </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/index.html" onClick="this.href=getDocIndex()"> DOC </a>
<td align="right">Handbuch der Java-Programmierung, 5. Auflage, Addison
Wesley, Version 5.0.1
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100260.html"> << </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100261.html"> < </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100263.html"> > </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100265.html"> >> </a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/api/index.html" onClick="this.href=getApiIndex()"> API </a>
<td align="right">© 1998, 2007 Guido Krüger & Thomas
Stark, <a href="http://www.javabuch.de">http://www.javabuch.de</a>
</table>
<a name="endofbody"></a>
</body>
</html>
|