objectoutputstream.java
来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 1,350 行 · 第 1/3 页
JAVA
1,350 行
/*
* @(#)ObjectOutputStream.java 1.35 98/02/05
*
* Copyright (c) 1995, 1996 Sun Microsystems, Inc. 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.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
* CopyrightVersion 1.1_beta
*/
package java.io;
import java.util.Stack;
import sun.io.ObjectOutputStreamDelegate; // RMI over IIOP hook.
/**
* An ObjectOutputStream writes primitive data types and graphs of
* Java objects to an OutputStream. The objects can be read
* (reconstituted) using an ObjectInputStream.
* Persistent storage of objects can be accomplished by using a file for
* the stream.
* If the stream is a network socket stream, the objects can be reconsituted
* on another host or in another process. <p>
*
* Only objects that support the java.io.Serializable interface can be
* written to streams.
*
* The class of each serializable object is encoded including the class
* name and signature of the class, the values of the
* object's fields and arrays, and the closure of any other objects
* referenced from the initial objects. <p>
*
* The method <STRONG>writeObject</STRONG> is used to write an object
* to the stream. Any object, including Strings and arrays, is
* written with writeObject. Multiple objects or primitives can be
* written to the stream. The objects must be read back from the
* corresponding ObjectInputstream with the same types and in the same
* order as they were written.<p>
*
* Primitive data types can also be written to the stream using the
* appropriate methods from DataOutput. Strings can also be written
* using the writeUTF method.<p>
*
* The default serialization mechanism for an object writes the class
* of the object, the class signature, and the values of all
* non-transient and non-static fields. References to other objects
* (except in transient or static fields) cause those objects to be
* written also. Multiple references to a single object are encoded
* using a reference sharing mechanism so that graphs of objects can
* be restored to the same shape as when the original was written. <p>
*
* For example to write an object that can be read by the example in ObjectInputStream: <br>
* <PRE>
* FileOutputStream ostream = new FileOutputStream("t.tmp");
* ObjectOutputStream p = new ObjectOutputStream(ostream);
*
* p.writeInt(12345);
* p.writeObject("Today");
* p.writeObject(new Date());
*
* p.flush();
* ostream.close();
*
* </PRE>
*
* Classes that require special handling during the serialization and deserialization
* process must implement special methods with these exact signatures: <p>
*
* <PRE>
* private void readObject(java.io.ObjectInputStream stream)
* throws IOException, ClassNotFoundException;
* private void writeObject(java.io.ObjectOutputStream stream)
* throws IOException
* </PRE><p>
* The writeObject method is responsible for writing the state of
* the object for its particular class so that the corresponding
* readObject method can restore it.
* The method does not need to concern itself with the
* state belonging to the object's superclasses or subclasses.
* State is saved by writing the individual fields to the ObjectOutputStream
* using the writeObject method or by using the methods for
* primitive data types supported by DataOutput. <p>
*
* Serialization does not write out 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>
*
* Serialization of an object can be prevented by implementing writeObject
* and readObject methods that throw the NotSerializableException.
* The exception will be caught by the ObjectOutputStream and abort the
* serialization 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.
*
* @author Roger Riggs
* @version 1.35, 02/05/98
* @see java.io.DataOutput
* @see java.io.ObjectInputStream
* @see java.io.Serializable
* @see java.io.Externalizable
* @since JDK1.1
*/
public class ObjectOutputStream
extends OutputStream
implements ObjectOutput, ObjectStreamConstants
{
/**
* Creates an ObjectOutputStream that writes to the specified OutputStream.
* The stream header is written to the stream. The caller may want to call
* flush immediately so that the corresponding ObjectInputStream can read
* the header immediately.
* @exception IOException Any exception thrown by the underlying OutputStream.
* @since JDK1.1
*/
public ObjectOutputStream(OutputStream out) throws IOException {
/*
* RMI over IIOP hook. Check if we are a trusted subclass
* that has implemented the "sun.io.ObjectOutputStream"
* interface. If so, set our private flag that will be
* checked in "writeObject", "defaultWriteObject" and
* "enableReplaceObject". 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.ObjectOutputStreamDelegate && this.getClass().getClassLoader() == null) {
isTrustedSubclass = true;
return;
}
this.out = out;
dos = new DataOutputStream(this);
buf = new byte[1024]; // allocate buffer
writeStreamHeader();
resetStream();
}
/**
* Write the specified object to the ObjectOutputStream.
* 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 written. Default serialization for a class can be
* overridden using the writeObject and the readObject methods.
* Objects referenced by this object are written transitively so
* that a complete equivalent graph of objects can be
* reconstructed by an ObjectInputStream. <p>
*
* Exceptions are thrown for
* problems with the OutputStream and for classes that should not be
* serialized. All exceptions are fatal to the OutputStream, which
* is left in an indeterminate state, and it is up to the caller
* to ignore or recover the stream state.
* @exception InvalidClassException Something is wrong with a class used by
* serialization.
* @exception NotSerializableException Some object to be serialized does not
* implement the java.io.Serializable interface.
* @exception IOException Any exception thrown by the underlying OutputStream.
* @since JDK1.1
*/
public final void writeObject(Object obj)
throws IOException
{
/*
* RMI over IIOP hook. Invoke delegate method if indicated.
*/
if (isTrustedSubclass) {
((ObjectOutputStreamDelegate) this).writeObjectDelegate(obj);
return;
}
Object prevObject = currentObject;
ObjectStreamClass prevClassDesc = currentClassDesc;
boolean oldBlockDataMode = setBlockData(false);
recursionDepth++;
try {
if (serializeNullAndRepeat(obj))
return;
if (checkSpecialClasses(obj))
return;
/* If the replacment is enabled, give subclasses one chance
* to substitute a new object. If one is substituted,
* recheck for null, repeated refs, and special cased classes
*/
if (enableReplace) {
Object altobj = replaceObject(obj);
if (obj != altobj) {
if (altobj != null && !(altobj instanceof Serializable)) {
String clname = altobj.getClass().getName();
throw new NotSerializableException(clname);
}
// If the alternate object is already
// serialized just remember the replacement
if (serializeNullAndRepeat(altobj)) {
addReplacement(obj, altobj);
return;
}
/* Add this to the set of replaced objects.
* This must be done before the object is
* serialized so that if the object indirectly
* refers to the original it will be redirected to
* the replacement.
*
* NB: checkSpecialClasses should only call
* serializeNullandRepeat for objects that will not
* recurse.
*/
addReplacement(obj, altobj);
if (checkSpecialClasses(altobj))
return;
obj = altobj;
}
}
if (checkSubstitutableSpecialClasses(obj))
return;
else {
/* Write out the object as itself */
outputObject(obj);
}
} catch (ObjectStreamException ee) {
if (abortIOException == null) {
try {
/* Prepare to write the exception to the stream.
* End blockdatamode in case it's set
* Write the exception code
* reset the stream to forget all previous objects
* write the exception that occurred
* reset the stream again so subsequent objects won't map to
* the exception or its args.
* Continue below to rethrow the exception.
*/
setBlockData(false);
writeCode(TC_EXCEPTION);
resetStream();
this.writeObject(ee);
resetStream();
// Set the pending exception to be rethrown.
abortIOException = ee;
} catch (IOException fatal) {
/* An exception occurred while writing the original exception to
* the stream. The original exception is not complete in
* the stream and recusion would be bad. Supercede the original
* Exception with a StreamCorruptedException using the message
* from this current exception.
*/
abortIOException =
new StreamCorruptedException(fatal.getMessage());
}
}
} catch (IOException ee) {
// Don't supercede a pending exception, the original will be re-thrown.
if (abortIOException == null)
abortIOException = ee;
} finally {
/* Restore state of previous call incase this is a nested call */
recursionDepth--;
currentObject = prevObject;
currentClassDesc = prevClassDesc;
setBlockData(oldBlockDataMode);
}
/* If the recursion depth is 0, test for and clear the pending exception.
* If there is a pending exception throw it.
*/
IOException pending = abortIOException;
if (recursionDepth == 0)
abortIOException = null;
if (pending != null) {
throw pending;
}
}
/*
* Check for special cases of serializing objects.
*/
private boolean checkSpecialClasses(Object obj) throws IOException {
/*
* If this is a class, don't allow substitution
*/
if (obj instanceof Class) {
outputClass((Class)obj);
return true;
}
if (obj instanceof ObjectStreamClass) {
outputClassDescriptor((ObjectStreamClass)obj);
return true;
}
return false;
}
/*
* Check for special cases of substitutable serializing objects.
* These classes are replaceable.
*/
private boolean checkSubstitutableSpecialClasses(Object obj)
throws IOException
{
if (obj instanceof String) {
outputString((String)obj);
return true;
}
if (obj.getClass().isArray()) {
outputArray(obj);
return true;
}
return false;
}
/**
* Write the non-static and non-transient fields of the current class
* to this stream. This may only be called from the writeObject method
* of the class being serialized. It will throw the NotActiveException
* if it is called otherwise.
* @since JDK1.1
*/
public final void defaultWriteObject() throws IOException {
/*
* RMI over IIOP hook. Invoke delegate method if indicated.
*/
if (isTrustedSubclass) {
((ObjectOutputStreamDelegate) this).defaultWriteObjectDelegate();
return;
}
if (currentObject == null || currentClassDesc == null)
throw new NotActiveException("defaultWriteObject");
if (currentClassDesc.getFieldSequence() != null) {
boolean prevmode = setBlockData(false);
outputClassFields(currentObject, currentClassDesc.forClass(),
currentClassDesc.getFieldSequence());
setBlockData(prevmode);
}
}
/**
* Reset will disregard the state of any objects already written
* to the stream. The state is reset to be the same as a new
* ObjectOutputStream. The current point in the stream is marked
* as reset so the corresponding ObjectInputStream will be reset
* at the same point. Objects previously written to the stream
* will not be refered to as already being in the stream. They
* will be written to the stream again.
* @since JDK1.1
*/
public void reset() throws IOException {
if (currentObject != null || currentClassDesc != null)
throw new IOException("Illegal call to reset");
/* Write a reset to the stream. */
setBlockData(false);
writeCode(TC_RESET);
resetStream(); // re-init the stream
abortIOException = null;
}
/*
* Internal reset function to reinitialize the state of the stream.
* Reset state of things changed by using the stream.
*/
private void resetStream() throws IOException {
if (wireHandle2Object == null) {
wireHandle2Object = new Object[100];
wireNextHandle = new int[100];
wireHash2Handle = new int[101];
} else {
// Storage Optimization for frequent calls to reset method.
// Do not reallocate, only reinitialize.
for (int i = 0; i < nextWireOffset; i++) {
wireHandle2Object[i] = null;
wireNextHandle[i] = 0;
}
}
nextWireOffset = 0;
for (int i = 0; i < wireHash2Handle.length; i++) {
wireHash2Handle[i] = -1;
}
if (classDescStack == null)
classDescStack = new Stack();
else
classDescStack.setSize(0);
for (int i = 0; i < nextReplaceOffset; i++)
replaceObjects[i] = null;
nextReplaceOffset = 0;
setBlockData(true); /* Re-enable buffering */
}
/**
* Subclasses may implement this method to allow class data to be stored
* in the stream. By default this method does nothing.
* The corresponding method in ObjectInputStream is resolveClass.
* This method is called exactly once for each unique class in the stream.
* The class name and signature will have already been written to the stream.
* This method may make free use of the ObjectOutputStream to save
* any representation of the class it deems suitable (for example,
* the bytes of the class file). The resolveClass method in the corresponding
* subclass of ObjectInputStream must read and use any data or objects
* written by annotateClass.
* annotateClass is called only for normal classes. Arrays are not normal classes.
* @exception IOException Any exception thrown by the underlying OutputStream.
* @since JDK1.1
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?