ObjectOutputStream and ObjectInputStream can provide an application with persistent storage for graphs of objects when used with a FileOutputStream and FileInputStream respectively. ObjectInputStream is used to recover those objects previously serialized. Other uses include passing objects between hosts using a socket stream or for marshaling and unmarshaling arguments and parameters in a remote communication system.
ObjectInputStream ensures that the types of all objects in the graph created from the stream match the classes present in the Java Virtual Machine. Classes are loaded as required using the standard mechanisms.
Only objects that support the java.io.Serializable or java.io.Externalizable interface can be read from streams.
The method readObject
is used to read an object from the
stream. Java's safe casting should be used to get the desired type. In
Java, strings and arrays are objects and are treated as objects during
serialization. When read they need to be cast to the expected type.
Primitive data types can be read from the stream using the appropriate method on DataInput.
The default deserialization mechanism for objects restores the contents of each field to the value and type it had when it was written. Fields declared as transient or static are ignored by the deserialization process. References to other objects cause those objects to be read from the stream as necessary. Graphs of objects are restored correctly using a reference sharing mechanism. New objects are always allocated when deserializing, which prevents existing objects from being overwritten.
Reading an object is analogous to running the constructors of a new object. Memory is allocated for the object and initialized to zero (NULL). No-arg constructors are invoked for the non-serializable classes and then the fields of the serializable classes are restored from the stream starting with the serializable class closest to java.lang.object and finishing with the object's most specific class.
For example to read from a stream as written by the example in
ObjectOutputStream:
FileInputStream fis = new FileInputStream("t.tmp"); ObjectInputStream ois = new ObjectInputStream(fis); int i = ois.readInt(); String today = (String) ois.readObject(); Date date = (Date) ois.readObject(); ois.close();
Classes control how they are serialized by implementing either the java.io.Serializable or java.io.Externalizable interfaces.
Implementing the Serializable interface allows object serialization to save and restore the entire state of the object and it allows classes to evolve between the time the stream is written and the time it is read. It automatically traverses references between objects, saving and restoring entire graphs.
Serializable classes that require special handling during the serialization and deserialization process should implement the following methods:
private void writeObject(java.io.ObjectOutputStream stream) throws IOException; private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException; private void readObjectNoData() throws ObjectStreamException;
The readObject method is responsible for reading and restoring the state of the object for its particular class using data written to the stream by the corresponding writeObject method. The method does not need to concern itself with the state belonging to its superclasses or subclasses. State is restored by reading data from the ObjectInputStream for the individual fields and making assignments to the appropriate fields of the object. Reading primitive data types is supported by DataInput.
Any attempt to read object data which exceeds the boundaries of the custom data written by the corresponding writeObject method will cause an OptionalDataException to be thrown with an eof field value of true. Non-object reads which exceed the end of the allotted data will reflect the end of data in the same way that they would indicate the end of the stream: bytewise reads will return -1 as the byte read or number of bytes read, and primitive reads will throw EOFExceptions. If there is no corresponding writeObject method, then the end of default serialized data marks the end of the allotted data.
Primitive and object read calls issued from within a readExternal method
behave in the same manner--if the stream is already positioned at the end of
data written by the corresponding writeExternal method, object reads will
throw OptionalDataExceptions with eof set to true, bytewise reads will
return -1, and primitive reads will throw EOFExceptions. Note that this
behavior does not hold for streams written with the old
ObjectStreamConstants.PROTOCOL_VERSION_1
protocol, in which the
end of data written by writeExternal methods is not demarcated, and hence
cannot be detected.
The readObjectNoData method is responsible for initializing the state of the object for its particular class in the event that the serialization stream does not list the given class as a superclass of the object being deserialized. This may occur in cases where the receiving party uses a different version of the deserialized instance's class than the sending party, and the receiver's version extends classes that are not extended by the sender's version. This may also occur if the serialization stream has been tampered; hence, readObjectNoData is useful for initializing deserialized objects properly despite a "hostile" or incomplete source stream.
Serialization does not read or assign values to the fields of any object that does not implement the java.io.Serializable interface. Subclasses of Objects that are not serializable can be serializable. In this case the non-serializable class must have a no-arg constructor to allow its fields to be initialized. In this case it is the responsibility of the subclass to save and restore the state of the non-serializable class. It is frequently the case that the fields of that class are accessible (public, package, or protected) or that there are get and set methods that can be used to restore the state.
Any exception that occurs while deserializing an object will be caught by the ObjectInputStream and abort the reading process.
Implementing the Externalizable interface allows the object to assume complete control over the contents and format of the object's serialized form. The methods of the Externalizable interface, writeExternal and readExternal, are called to save and restore the objects state. When implemented by a class they can write and read their own state using all of the methods of ObjectOutput and ObjectInput. It is the responsibility of the objects to handle any versioning that occurs.
Enum constants are deserialized differently than ordinary serializable or
externalizable objects. The serialized form of an enum constant consists
solely of its name; field values of the constant are not transmitted. To
deserialize an enum constant, ObjectInputStream reads the constant name from
the stream; the deserialized constant is then obtained by calling the static
method Enum.valueOf(Class, String)
with the enum constant's
base type and the received constant name as arguments. Like other
serializable or externalizable objects, enum constants can function as the
targets of back references appearing subsequently in the serialization
stream. The process by which enum constants are deserialized cannot be
customized: any class-specific readObject, readObjectNoData, and readResolve
methods defined by enum types are ignored during deserialization.
Similarly, any serialPersistentFields or serialVersionUID field declarations
are also ignored--all enum types have a fixed serialVersionUID of 0L.
If a security manager is installed, this constructor will check for the "enableSubclassImplementation" SerializablePermission when invoked directly or indirectly by the constructor of a subclass which overrides the ObjectInputStream.readFields or ObjectInputStream.readUnshared methods.
All externalizable data is written in JDK 1.1 external data format after calling this method. This version is needed to write streams containing Externalizable data that can be read by pre-JDK 1.1.6 JVMs.
This protocol is written by JVM 1.2. Externalizable data is written in block data mode and is terminated with TC_ENDBLOCKDATA. Externalizable classdescriptor flags has SC_BLOCK_DATA enabled. JVM 1.1.6 and greater can read this format change. Enables writing a nonSerializable class descriptor into the stream. The serialVersionUID of a nonSerializable class is set to 0L.
The equals
method implements an equivalence relation
on non-null object references:
x
, x.equals(x)
should return
true
.
x
and y
, x.equals(y)
should return true
if and only if
y.equals(x)
returns true
.
x
, y
, and z
, if
x.equals(y)
returns true
and
y.equals(z)
returns true
, then
x.equals(z)
should return true
.
x
and y
, multiple invocations of
x.equals(y) consistently return true
or consistently return false
, provided no
information used in equals
comparisons on the
objects is modified.
x
,
x.equals(null)
should return false
.
The equals method for class Object
implements
the most discriminating possible equivalence relation on objects;
that is, for any non-null reference values x
and
y
, this method returns true
if and only
if x
and y
refer to the same object
(x == y
has the value true
).
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
java.util.Hashtable
.
The general contract of hashCode
is:
hashCode
method on each of
the two objects must produce the same integer result.
As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)
reset
method repositions this stream at the last marked
position so that subsequent reads re-read the same bytes.
The readlimit
arguments tells this input stream to
allow that many bytes to be read before the mark position gets
invalidated.
The general contract of mark
is that, if the method
markSupported
returns true
, the stream somehow
remembers all the bytes read after the call to mark
and
stands ready to supply those same bytes again if and whenever the method
reset
is called. However, the stream is not required to
remember any data at all if more than readlimit
bytes are
read from the stream before reset
is called.
The mark
method of InputStream
does
nothing.
mark
and
reset
methods. Whether or not mark
and
reset
are supported is an invariant property of a
particular input stream instance. The markSupported
method
of InputStream
returns false
.wait
methods.
The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:
synchronized
statement
that synchronizes on the object.
Class,
by executing a
synchronized static method of that class.
Only one thread at a time can own an object's monitor.
wait
methods.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object. The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.
This method should only be called by a thread that is the owner
of this object's monitor. See the notify
method for a
description of the ways in which a thread can become the owner of
a monitor.
b
. The number of bytes actually read is
returned as an integer. This method blocks until input data is
available, end of file is detected, or an exception is thrown.
If b
is null
, a
NullPointerException
is thrown. If the length of
b
is zero, then no bytes are read and 0
is
returned; otherwise, there is an attempt to read at least one byte. If
no byte is available because the stream is at end of file, the value
-1
is returned; otherwise, at least one byte is read and
stored into b
.
The first byte read is stored into element b[0]
, the
next one into b[1]
, and so on. The number of bytes read is,
at most, equal to the length of b
. Let k be the
number of bytes actually read; these bytes will be stored in elements
b[0]
through b[
k-1]
,
leaving elements b[
k]
through
b[b.length-1]
unaffected.
If the first byte cannot be read for any reason other than end of
file, then an IOException
is thrown. In particular, an
IOException
is thrown if the input stream has been closed.
The read(b)
method for class InputStream
has the same effect as:
read(b, 0, b.length)
However, for objects which are not enum constants or instances of java.lang.Class and do not define readResolve methods, readUnshared guarantees that the returned object reference is unique and cannot be obtained a second time from the ObjectInputStream that created it, even if the underlying data stream has been manipulated. This guarantee applies only to the base-level object returned by readUnshared, and not to any transitively referenced sub-objects in the returned object graph.
ObjectInputStream subclasses which override this method can only be constructed in security contexts possessing the "enableSubclassImplementation" SerializablePermission; any attempt to instantiate such a subclass without this permission will cause a SecurityException to be thrown.
mark
method was last called on this input stream.
The general contract of reset
is:
markSupported
returns
true
, then:
mark
has not been called since
the stream was created, or the number of bytes read from the stream
since mark
was last called is larger than the argument
to mark
at that last call, then an
IOException
might be thrown.
IOException
is not thrown, then the
stream is reset to a state such that all the bytes read since the
most recent call to mark
(or since the start of the
file, if mark
has not been called) will be resupplied
to subsequent callers of the read
method, followed by
any bytes that otherwise would have been the next input data as of
the time of the call to reset
. markSupported
returns
false
, then:
reset
may throw an
IOException
.
IOException
is not thrown, then the stream
is reset to a fixed state that depends on the particular type of the
input stream and how it was created. The bytes that will be supplied
to subsequent callers of the read
method depend on the
particular type of the input stream. The method reset
for class InputStream
does nothing except throw an IOException
.
n
bytes of data from this input
stream. The skip
method may, for a variety of reasons, end
up skipping over some smaller number of bytes, possibly 0
.
This may result from any of a number of conditions; reaching end of file
before n
bytes have been skipped is only one possibility.
The actual number of bytes skipped is returned. If n
is
negative, no bytes are skipped.
The skip
method of InputStream
creates a
byte array and then repeatedly reads into it until n
bytes
have been read or the end of the stream has been reached. Subclasses are
encouraged to provide a more efficient implementation of this method.
toString
method returns a string that
"textually represents" this object. The result should
be a concise but informative representation that is easy for a
person to read.
It is recommended that all subclasses override this method.
The toString
method for class Object
returns a string consisting of the name of the class of which the
object is an instance, the at-sign character `@
', and
the unsigned hexadecimal representation of the hash code of the
object. In other words, this method returns a string equal to the
value of:
getClass().getName() + '@' + Integer.toHexString(hashCode())
The current thread must own this object's monitor. The thread
releases ownership of this monitor and waits until another thread
notifies threads waiting on this object's monitor to wake up
either through a call to the notify
method or the
notifyAll
method. The thread then waits until it can
re-obtain ownership of the monitor and resumes execution.
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition }This method should only be called by a thread that is the owner of this object's monitor. See the
notify
method for a
description of the ways in which a thread can become the owner of
a monitor.The current thread must own this object's monitor.
This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object. Thread T becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:
A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:
synchronized (obj) { while (<condition does not hold>) obj.wait(timeout); ... // Perform action appropriate to condition }(For more information on this topic, see Section 3.2.3 in Doug Lea's "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, 2000), or Item 50 in Joshua Bloch's "Effective Java Programming Language Guide" (Addison-Wesley, 2001).
If the current thread is interrupted by another thread while it is waiting, then an InterruptedException is thrown. This exception is not thrown until the lock status of this object has been restored as described above.
Note that the wait method, as it places the current thread into the wait set for this object, unlocks only this object; any other objects on which the current thread may be synchronized remain locked while the thread waits.
This method should only be called by a thread that is the owner
of this object's monitor. See the notify
method for a
description of the ways in which a thread can become the owner of
a monitor.
This method is similar to the wait
method of one
argument, but it allows finer control over the amount of time to
wait for a notification before giving up. The amount of real time,
measured in nanoseconds, is given by:
1000000*timeout+nanos
In all other respects, this method does the same thing as the method of one argument. In particular, wait(0, 0) means the same thing as wait(0).
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until either of the following two conditions has occurred:
notify
method
or the notifyAll
method.
timeout
milliseconds plus nanos
nanoseconds arguments, has
elapsed.
The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
synchronized (obj) { while (<condition does not hold>) obj.wait(timeout, nanos); ... // Perform action appropriate to condition }This method should only be called by a thread that is the owner of this object's monitor. See the
notify
method for a
description of the ways in which a thread can become the owner of
a monitor.