objectinputstream.java
来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 1,730 行 · 第 1/4 页
JAVA
1,730 行
/*
* @(#)ObjectInputStream.java 1.41 98/07/09
*
* Copyright 1995-1998 by Sun Microsystems, Inc.,
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
* All rights reserved.
*
* This software is the confidential and proprietary information
* of Sun Microsystems, Inc. ("Confidential Information"). You
* shall not disclose such Confidential Information and shall use
* it only in accordance with the terms of the license agreement
* you entered into with Sun.
*/
package java.io;
import java.util.Vector;
import java.util.Stack;
import java.util.Hashtable;
import sun.io.ObjectInputStreamDelegate; // RMI over IIOP hook.
/**
* An ObjectInputStream deserializes primitive data and objects previously
* written using an ObjectOutputStream.
*
* 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.<p>
*
* 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. <p>
*
* Only objects that support the java.io.Serializable or
* java.io.Externalizable interface can be read from streams.
*
* The method <STRONG>readObject</STRONG> 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.<p>
*
* Primitive data types can be read from the stream using the appropriate
* method on DataInput. <p>
*
* 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. <p>
*
* 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 specifiec
* class. <p>
*
* For example to read from a stream as written by the example in
* ObjectOutputStream: <br>
*
* <PRE>
* FileInputStream istream = new FileInputStream("t.tmp");
* ObjectInputStream p = new ObjectInputStream(istream);
*
* int i = p.readInt();
* String today = (String)p.readObject();
* Date date = (Date)p.readObject();
*
* istream.close();
* </PRE>
*
* Classes control how they are serialized by implementing either the
* java.io.Serializable or java.io.Externalizable interfaces.<P>
*
* 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 both
* of these methods:<p>
*
* <PRE>
* private void writeObject(java.io.ObjectOutputStream stream)
* throws IOException;
* private void readObject(java.io.ObjectInputStream stream)
* throws IOException, ClassNotFoundException;
* </PRE><p>
*
* 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. <p>
*
* 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. <p>
*
* Any exception that occurs while deserializing an object will be
* caught by the ObjectInputStream and abort the reading process. <p>
*
* 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.
*
* @author Roger Riggs
* @version 1.41, 07/09/98
* @see java.io.DataInput
* @see java.io.ObjectOutputStream
* @see java.io.Serializable
* @since JDK1.1
*/
public class ObjectInputStream extends InputStream
implements ObjectInput, ObjectStreamConstants
{
/**
* Create an ObjectInputStream that reads from the specified InputStream.
* The stream header containing the magic number and version number
* are read from the stream and verified. This method will block
* until the corresponding ObjectOutputStream has written and flushed the header.
* @exception StreamCorruptedException The version or magic number are incorrect.
* @exception IOException An exception occurred in the underlying stream.
* @since JDK1.1
*/
public ObjectInputStream(InputStream in)
throws IOException, StreamCorruptedException
{
/*
* RMI over IIOP hook. Check if we are a trusted subclass
* that has implemented the "sun.io.ObjectInputStream"
* interface. If so, set our private flag that will be
* checked in "readObject", "defaultReadObject" and
* "enableResolveObject". Note that we don't initialize
* private instance variables in this case as an optimization
* (subclasses using the hook should have no need for them).
*/
if (this instanceof sun.io.ObjectInputStreamDelegate && this.getClass().getClassLoader() == null) {
isTrustedSubclass = true;
return;
}
/*
* Save the input stream to read bytes from
* Create a DataInputStream used to read primitive types.
* Setup the DataInputStream to read from this ObjectInputStream
*/
this.in = in;
dis = new DataInputStream(this);
readStreamHeader();
resetStream();
}
/**
* Read an object from the ObjectInputStream.
* The class of the object, the signature of the class, and the values
* of the non-transient and non-static fields of the class and all
* of its supertypes are read. Default deserializing for a class can be
* overriden using the writeObject and readObject methods.
* Objects referenced by this object are read transitively so
* that a complete equivalent graph of objects is reconstructed by readObject. <p>
*
* The root object is completly restored when all of its fields
* and the objects it references are completely restored. At this
* point the object validation callbacks are executed in order
* based on their registered priorities. The callbacks are
* registered by objects (in the readObject special methods)
* as they are individually restored.
*
* Exceptions are thrown for problems with the InputStream and for classes
* that should not be deserialized. All exceptions are fatal to the
* InputStream and leave it in an indeterminate state; it is up to the caller
* to ignore or recover the stream state.
* @exception java.lang.ClassNotFoundException Class of a serialized object
* cannot be found.
* @exception InvalidClassException Something is wrong with a class used by
* serialization.
* @exception StreamCorruptedException Control information in the
* stream is inconsistent.
* @exception OptionalDataException Primitive data was found in the
* stream instead of objects.
* @exception IOException Any of the usual Input/Output related exceptions.
* @since JDK1.1
*/
public final Object readObject()
throws OptionalDataException, ClassNotFoundException, IOException {
/*
* RMI over IIOP hook. Invoke delegate method if indicated.
*/
if (isTrustedSubclass) {
return ((ObjectInputStreamDelegate) this).readObjectDelegate();
}
/* require local Class for object by default. */
return readObject(true);
}
/*
* Private implementation of Read an object from the ObjectInputStream.
*
* @param requireLocalClass If false, do not throw ClassNotFoundException
* when local class does not exist.
*
* @since JDK1.2
*/
private final Object readObject(boolean requireLocalClass)
throws OptionalDataException, ClassNotFoundException, IOException
{
/* If the stream is in blockData mode and there's any data
* left throw an exception to report how much there is.
*/
if (blockDataMode) {
/* Can't use member method available() since it depends on the unreliable
* method InputStream.available().
*/
if (count == 0)
refill();
if (count > 0)
throw new OptionalDataException(count);
}
/*
* Look ahead now to absorb any pending reset's.
* Before changing the state.
*/
peekCode();
/* Save the current state and get ready to read an object. */
Object prevObject = currentObject;
ObjectStreamClass prevClass = currentClassDesc;
boolean prevBlockDataMode = setBlockData(false);
recursionDepth++; // Entering
Object obj = null;
/*
* Check for reset, handle it before reading an object.
*/
byte rcode;
rcode = readCode();
try {
/*
* Dispatch on the next code in the stream.
*/
int wireoffset = -1;
switch (rcode) {
case TC_NULL:
obj = null;
break;
case TC_REFERENCE:
/* This is a reference to a pre-existing object */
wireoffset = readInt() - baseWireHandle;
try {
obj = wireHandle2Object.elementAt(wireoffset);
} catch (ArrayIndexOutOfBoundsException e) {
throw new StreamCorruptedException("Reference to object never serialized.");
}
break;
case TC_STRING:
{
obj = readUTF();
Object localObj = obj; //readUTF does not set currentObject
wireoffset = assignWireOffset(obj);
/* Allow subclasses to replace the object */
if (enableResolve) {
obj = resolveObject(obj);
}
if (obj != localObj)
wireHandle2Object.setElementAt(obj, wireoffset);
}
break;
case TC_CLASS:
ObjectStreamClass v =
(ObjectStreamClass)readObject(requireLocalClass);
if (v == null) {
/*
* No class descriptor in stream or class not serializable
*/
throw new StreamCorruptedException("Class not in stream");
}
obj = v.forClass();
if (obj == null && requireLocalClass) {
throw new ClassNotFoundException(v.getName());
}
assignWireOffset(obj);
break;
case TC_CLASSDESC:
obj = inputClassDescriptor();
break;
case TC_ARRAY:
wireoffset = inputArray(requireLocalClass);
obj = currentObject;
/* Allow subclasses to replace the object */
if (enableResolve) {
obj = resolveObject(obj);
}
if (obj != currentObject)
wireHandle2Object.setElementAt(obj, wireoffset);
break;
case TC_OBJECT:
wireoffset = inputObject(requireLocalClass);
obj = currentObject;
if (enableResolve) {
/* Hook for alternate object */
obj = resolveObject(obj);
wireHandle2Object.setElementAt(obj, wireoffset);
}
break;
case TC_ENDBLOCKDATA:
if (!prevBlockDataMode)
throw new StreamCorruptedException("Unexpected end of block data");
pushbackCode(TC_ENDBLOCKDATA);
count = -1; /* Flag EOF */
throw new OptionalDataException(true);
case TC_BLOCKDATA:
case TC_BLOCKDATALONG:
if (rcode == TC_BLOCKDATALONG) { /* long block: 32 bit size */
int b3 = in.read();
int b2 = in.read();
int b1 = in.read();
int b0 = in.read();
if ((b3 | b2 | b1 | b0) < 0)
throw new StreamCorruptedException("EOF expecting count");
count = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
if (count < 0)
throw new StreamCorruptedException("Negative block data size");
} else { /* normal block: 8 bit size */
count = in.read();
if (count < 0)
throw new StreamCorruptedException("EOF expecting count");
}
if (!prevBlockDataMode)
throw new StreamCorruptedException("Unexpected blockdata");
throw new OptionalDataException(count);
case TC_EXCEPTION:
/* An exception happened during writing, reset the
* stream, read the exception, reset the stream and
* throw a writeAbortedException with the exception
* that was read.
*/
resetStream();
IOException ee = (IOException)readObject();
resetStream();
throw new WriteAbortedException("Writing aborted by exception", ee);
default:
throw new StreamCorruptedException("Unknown code in readObject " + rcode);
}
} catch (OptionalDataException optdata) {
/* OptionalDataExceptions won't terminate everything.
* so just rethrow it.
*/
throw optdata;
} catch(IOException ee) {
if (abortIOException == null && abortClassNotFoundException == null)
abortIOException = ee;
} catch(ClassNotFoundException ee) {
if (abortIOException == null && abortClassNotFoundException == null)
abortClassNotFoundException = ee;
} finally {
recursionDepth --;
currentObject = prevObject;
currentClassDesc = prevClass;
currentClass = currentClassDesc != null ?
currentClassDesc.forClass() : null;
setBlockData(prevBlockDataMode);
}
/* Check for thrown exceptions and re-throw them, clearing them if
* this is the last recursive call .
*/
IOException exIOE = abortIOException;
if (recursionDepth == 0)
abortIOException = null;
if (exIOE != null)
throw exIOE;
ClassNotFoundException exCNF = abortClassNotFoundException;
if (recursionDepth == 0)
abortClassNotFoundException = null;
if (exCNF != null) {
throw exCNF;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?