📄 tij0116.html
字号:
<html><body>
<table width="100%"><tr>
<td>
<a href="http://www.bruceeckel.com/javabook.html">Bruce Eckel's Thinking in Java</a>
</td>
<td align="right">
<a href="tij_c.html">Contents</a> | <a href="tij0115.html">Prev</a> | <a href="tij0117.html">Next</a>
</td>
</tr></table>
<hr>
<H2 ALIGN=LEFT>
Object
serialization
</H2>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Java
1.1<A NAME="Index1302"></A>
has added an interesting feature called <A NAME="Index1303"></A><A NAME="Index1304"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>object
serialization
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
that allows you to take any object that implements the <A NAME="Index1305"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Serializable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
interface and turn it into a sequence of bytes that can later be restored fully
into the original object. This is even true across a network, which means that
the serialization mechanism automatically compensates for differences in
operating systems. That is, you can create an object on a Windows machine,
serialize it, and send it across the network to a Unix machine where it will be
correctly reconstructed. You don’t have to worry about the data
representations on the different machines, the byte ordering, or any other
details.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">By
itself, object serialization is interesting because it allows you to implement <A NAME="Index1306"></A><A NAME="Index1307"></A><A NAME="Index1308"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>lightweight
persistence
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Remember that persistence means an object’s lifetime is not determined by
whether a program is executing – the object lives
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>in</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>between</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
invocations of the program. By taking a serializable object and writing it to
disk, then restoring that object when the program is re-invoked, you’re
able to produce the effect of persistence. The reason it’s called
“lightweight” is that you can’t simply define an object using
some kind of “persistent” keyword and let the system take care of
the details (although this might happen in the future). Instead, you must
explicitly serialize and de-serialize the objects in your program.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Object
serialization was added to the language to support two major features. Java 1.1<A NAME="Index1309"></A>’s
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>remote
method invocation
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(RMI) allows objects that live on other machines to behave as if they live on
your machine. When sending messages to remote objects, object serialization is
necessary to transport the arguments and return values. RMI is discussed in
Chapter 15.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Object
serialization is also necessary for Java Beans, introduced in Java 1.1<A NAME="Index1310"></A>.
When a Bean is used, its state information is generally configured at design
time. This state information must be stored and later recovered when the
program is started; object serialization performs this task.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Serializing
an object is quite simple, as long as the object implements the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Serializable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
interface (this interface is just a flag and has no methods). In Java 1.1<A NAME="Index1311"></A>,
many standard library classes have been changed so they’re serializable,
including all of the wrappers for the primitive types, all of the collection
classes, and many others. Even
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Class</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
objects can be serialized. (See Chapter 11 for the implications of this.)
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">To
serialize an object, you create some sort of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>OutputStream</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object and then wrap it inside an <A NAME="Index1312"></A><A NAME="Index1313"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ObjectOutputStream</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object. At this point you need only call <A NAME="Index1314"></A><A NAME="Index1315"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>writeObject( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and your object is serialized and sent to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>OutputStream</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
To reverse the process, you wrap an
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>InputStream</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
inside an
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ObjectInputStream</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and call <A NAME="Index1316"></A><A NAME="Index1317"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>readObject( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
What comes back is, as usual, a handle to an upcast
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
so you must downcast to set things straight.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">A
particularly clever aspect of object serialization is that it not only saves an
image of your object but it also follows all the handles contained in your
object and saves
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>those
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">objects,
and follows all the handles in each of those objects, etc. This is sometimes
referred to as the “<A NAME="Index1318"></A><A NAME="Index1319"></A>web
of objects” that a single object can be connected to, and it includes
arrays of handles to objects as well as member objects. If you had to maintain
your own object serialization scheme, maintaining the code to follow all these
links would be a bit mind–boggling. However, Java object serialization
seems to pull it off flawlessly, no doubt using an optimized algorithm that
traverses the web of objects. The following example tests the serialization
mechanism by making a “worm” of linked objects, each of which has a
link to the next segment in the worm as well as an array of handles to objects
of a different class,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Data</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">:</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: Worm.java</font>
<font color="#009900">// Demonstrates object serialization in Java 1.1</font>
<font color="#0000ff">import</font> java.io.*;
<font color="#0000ff">class</font> Data <font color="#0000ff">implements</font> Serializable {
<font color="#0000ff">private</font> <font color="#0000ff">int</font> i;
Data(<font color="#0000ff">int</font> x) { i = x; }
<font color="#0000ff">public</font> String toString() {
<font color="#0000ff">return</font> Integer.toString(i);
}
}
<font color="#0000ff">public</font> <font color="#0000ff">class</font> Worm <font color="#0000ff">implements</font> Serializable {
<font color="#009900">// Generate a random int value:</font>
<font color="#0000ff">private</font> <font color="#0000ff">static</font> <font color="#0000ff">int</font> r() {
<font color="#0000ff">return</font> (<font color="#0000ff">int</font>)(Math.random() * 10);
}
<font color="#0000ff">private</font> Data[] d = {
<font color="#0000ff">new</font> Data(r()), <font color="#0000ff">new</font> Data(r()), <font color="#0000ff">new</font> Data(r())
};
<font color="#0000ff">private</font> Worm next;
<font color="#0000ff">private</font> <font color="#0000ff">char</font> c;
<font color="#009900">// Value of i == number of segments</font>
Worm(<font color="#0000ff">int</font> i, <font color="#0000ff">char</font> x) {
System.out.println(" Worm constructor: " + i);
c = x;
<font color="#0000ff">if</font>(--i > 0)
next = <font color="#0000ff">new</font> Worm(i, (<font color="#0000ff">char</font>)(x + 1));
}
Worm() {
System.out.println("Default constructor");
}
<font color="#0000ff">public</font> String toString() {
String s = ":" + c + "(";
<font color="#0000ff">for</font>(<font color="#0000ff">int</font> i = 0; i < d.length; i++)
s += d[i].toString();
s += ")";
<font color="#0000ff">if</font>(next != <font color="#0000ff">null</font>)
s += next.toString();
<font color="#0000ff">return</font> s;
}
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
Worm w = <font color="#0000ff">new</font> Worm(6, 'a');
System.out.println("w = " + w);
<font color="#0000ff">try</font> {
ObjectOutputStream out =
<font color="#0000ff">new</font> ObjectOutputStream(
<font color="#0000ff">new</font> FileOutputStream("worm.out"));
out.writeObject("Worm storage");
out.writeObject(w);
out.close(); <font color="#009900">// Also flushes output</font>
ObjectInputStream in =
<font color="#0000ff">new</font> ObjectInputStream(
<font color="#0000ff">new</font> FileInputStream("worm.out"));
String s = (String)in.readObject();
Worm w2 = (Worm)in.readObject();
System.out.println(s + ", w2 = " + w2);
} <font color="#0000ff">catch</font>(Exception e) {
e.printStackTrace();
}
<font color="#0000ff">try</font> {
ByteArrayOutputStream bout =
<font color="#0000ff">new</font> ByteArrayOutputStream();
ObjectOutputStream out =
<font color="#0000ff">new</font> ObjectOutputStream(bout);
out.writeObject("Worm storage");
out.writeObject(w);
out.flush();
ObjectInputStream in =
<font color="#0000ff">new</font> ObjectInputStream(
<font color="#0000ff">new</font> ByteArrayInputStream(
bout.toByteArray()));
String s = (String)in.readObject();
Worm w3 = (Worm)in.readObject();
System.out.println(s + ", w3 = " + w3);
} <font color="#0000ff">catch</font>(Exception e) {
e.printStackTrace();
}
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">To
make things interesting, the array of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Data</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
objects inside
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Worm</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
are initialized with random numbers. (This way you don’t suspect the
compiler of keeping some kind of meta-information.) Each
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Worm</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
segment is labeled with a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>char</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
that’s automatically generated in the process of recursively generating
the linked list of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Worm</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s.
When you create a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Worm</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
you tell the constructor how long you want it to be. To make the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>next</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
handle it calls the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Worm</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
constructor with a length of one less, etc. The final
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>next</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
handle is left as
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>null</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
indicating the end of the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -