objectoutputstream.java
来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 1,350 行 · 第 1/3 页
JAVA
1,350 行
*/
protected void annotateClass(Class cl)
throws IOException
{
}
/** This method will allow trusted subclasses of ObjectOutputStream
* to substitute one object for another during
* serialization. Replacing objects is disabled until
* enableReplaceObject is called. The enableReplaceObject method
* checks that the stream requesting to do replacment can be
* trusted. Every reference to serializable objects is passed to
* replaceObject. To insure that the private state of objects is
* not unintentionally exposed only trusted streams may use
* replaceObject. <p>
*
* When a subclass is replacing objects it must insure that either
* a complementary substitution must be made during
* deserialization or that the substituted object is compatible
* with every field where the reference will be stored. Objects
* whose type is not a subclass of the type of the field or array
* element abort the serialization by raising an exception and the
* object is not be stored. <p>
*
* This method is called only once when each object is first encountered.
* All subsequent references to the object will be redirected to the
* new object. This method should return the object to be substituted or
* the original object. <P>
*
* Null can be returned as the object to be substituted, but may
* cause NullReferenceException in classes that contain references
* to the original object since they may be expecting an object
* instead of null.<p>
*
* @exception IOException Any exception thrown by the underlying
* OutputStream.
* @since JDK1.1
*/
protected Object replaceObject(Object obj)
throws IOException
{
return obj;
}
/**
* Enable the stream to do replacement of objects in the stream.
* If the stream is a trusted class it is allowed to enable replacement.
* Trusted classes are those classes with a classLoader equals null. <p>
*
* When enabled the replaceObject method is called for every object
* being serialized.
*
* @exception SecurityException The classloader of this stream object is non-null.
* @since JDK1.1
*/
protected final boolean enableReplaceObject(boolean enable)
throws SecurityException
{
/*
* RMI over IIOP hook. Invoke delegate method if indicated.
*/
if (isTrustedSubclass) {
return ((ObjectOutputStreamDelegate) this).enableReplaceObjectDelegate(enable);
}
boolean previous = enableReplace;
if (enable) {
ClassLoader loader = this.getClass().getClassLoader();
if (loader == null) {
enableReplace = true;
return previous;
}
throw new SecurityException("Not trusted class");
} else {
enableReplace = false;
}
return previous;
}
/**
* The writeStreamHeader method is provided so subclasses can
* append or prepend their own header to the stream.
* It writes the magic number and version to the stream.
* @since JDK1.1
*/
protected void writeStreamHeader() throws IOException {
writeShort(STREAM_MAGIC);
writeShort(STREAM_VERSION);
}
/**
* Write a string to the stream.
* Note that since Strings are Objects, writeObject
* will behave identically.
*/
private void outputString(String s) throws IOException {
/* Allocate a write handle but don't write it to the stream,
* Write out the code for a string,
* the read can regenerate the same sequence and it saves bytes.
*/
assignWireOffset(s);
writeCode(TC_STRING);
writeUTF(s);
}
/* Classes are special, they can not created during deserialization,
* but the appropriate class can be found.
*/
private void outputClass(Class aclass) throws IOException {
writeCode(TC_CLASS);
/* Find the class descriptor and write it out */
ObjectStreamClass v = ObjectStreamClass.lookup(aclass);
if (v == null)
throw new NotSerializableException(aclass.getName());
outputClassDescriptor(v);
assignWireOffset(aclass);
}
/* Write the class descriptor */
private void outputClassDescriptor(ObjectStreamClass classdesc)
throws IOException
{
if (serializeNullAndRepeat(classdesc))
return;
/* Write out the code for a class
* Write out the class name and its serialVersionUID
*/
writeCode(TC_CLASSDESC);
String classname = classdesc.getName();
writeUTF(classname);
writeLong(classdesc.getSerialVersionUID());
/* This is done here to be symetric with the inputClass method
* Since the resolveClassName() method may use the stream.
* The assignments of wirehandles must be done in the same order
*/
assignWireOffset(classdesc);
/* Write the version description for this class */
classdesc.write(this);
/* Give subclassers a chance to add the class implementation
* to the stream. Set BlockData mode so any information they
* write can be skipped on reading.
*/
boolean prevMode = setBlockData(true);
annotateClass(classdesc.forClass());
setBlockData(prevMode);
writeCode(TC_ENDBLOCKDATA);
/*
* Write out the superclass descriptor of this descriptor
* only if it is for a java.io.Serializable class.
* else write null.
*/
ObjectStreamClass superdesc = classdesc.getSuperclass();
outputClassDescriptor(superdesc);
}
/**
* Write an array out. Note that since Arrays are Objects, writeObject(obj)
* will behave identically. <br><br>
* @param o can represent an array of any type/dimension.
*/
private void outputArray(Object obj)
throws IOException
{
Class currclass = obj.getClass();
ObjectStreamClass v = ObjectStreamClass.lookup(currclass);
/* Write out the code for an array and the name of the class */
writeCode(TC_ARRAY);
outputClassDescriptor(v);
/* Assign the wirehandle for this object and outputArrayValues
* writes the length and the array contents.
*/
assignWireOffset(obj);
int i, length;
Class type = currclass.getComponentType();
if (type.isPrimitive()) {
/* Write arrays of primitive types using the DataOutput
* methods that convert each element into the output buffer.
* The data types are ordered by the frequency
* in which they are expected to occur.
*/
if (type == Integer.TYPE) {
int[] array = (int[])obj;
length = array.length;
writeInt(length);
for (i = 0; i < length; i++) {
writeInt(array[i]);
}
} else if (type == Byte.TYPE) {
byte[] array = (byte[])obj;
length = array.length;
writeInt(length);
writeInternal(array, 0, length, true);
} else if (type == Long.TYPE) {
long[] array = (long[])obj;
length = array.length;
writeInt(length);
for (i = 0; i < length; i++) {
writeLong(array[i]);
}
} else if (type == Float.TYPE) {
float[] array = (float[])obj;
length = array.length;
writeInt(length);
for (i = 0; i < length; i++) {
writeFloat(array[i]);
}
} else if (type == Double.TYPE) {
double[] array = (double[])obj;
length = array.length;
writeInt(length);
for (i = 0; i < length; i++) {
writeDouble(array[i]);
}
} else if (type == Short.TYPE) {
short[] array = (short[])obj;
length = array.length;
writeInt(length);
for (i = 0; i < length; i++) {
writeShort(array[i]);
}
} else if (type == Character.TYPE) {
char[] array = (char[])obj;
length = array.length;
writeInt(length);
for (i = 0; i < length; i++) {
writeChar(array[i]);
}
} else if (type == Boolean.TYPE) {
boolean[] array = (boolean[])obj;
length = array.length;
writeInt(length);
for (i = 0; i < length; i++) {
writeBoolean(array[i]);
}
} else {
throw new InvalidClassException(currclass.getName());
}
} else {
Object[] array = (Object[])obj;
length = array.length;
writeInt(length);
for (i = 0; i < length; i++) {
writeObject(array[i]);
}
}
}
/*
* Put the object into the stream The newObject code is written
* followed by the ObjectStreamClass for the object's class. Each
* of the objects classes is written using the default
* serialization code and dispatching to Specials where
* appropriate.
*/
private void outputObject(Object obj)
throws IOException
{
currentObject = obj;
Class currclass = obj.getClass();
/* Get the Class descriptor for this class,
* Throw a NotSerializableException if there is none.
*/
currentClassDesc = ObjectStreamClass.lookup(currclass);
if (currentClassDesc == null) {
throw new NotSerializableException(currclass.getName());
}
/* Write the code to expect an instance and
* the class descriptor of the instance
*/
writeCode(TC_OBJECT);
outputClassDescriptor(currentClassDesc);
/* Assign the next wirehandle */
assignWireOffset(obj);
/* If the object is externalizable,
* call writeExternal.
* else do Serializable processing.
*/
if (currentClassDesc.isExternalizable()) {
Externalizable ext = (Externalizable)obj;
ext.writeExternal(this);
} else {
/* The object's classes should be processed from supertype to subtype
* Push all the clases of the current object onto a stack.
* Remember the stack pointer where this set of classes is being pushed.
*/
int stackMark = classDescStack.size();
try {
ObjectStreamClass next;
while ((next = currentClassDesc.getSuperclass()) != null) {
classDescStack.push(currentClassDesc);
currentClassDesc = next;
}
/*
* For currentClassDesc and all the pushed class descriptors
* If the class is writing its own data
* set blockData = true; call the class writeObject method
* If not
* invoke either the defaultWriteObject method.
*/
do {
if (currentClassDesc.hasWriteObject()) {
setBlockData(true); /* Block any data the class writes */
invokeObjectWriter(obj, currentClassDesc.forClass());
setBlockData(false);
writeCode(TC_ENDBLOCKDATA);
} else {
defaultWriteObject();
}
} while (classDescStack.size() > stackMark &&
(currentClassDesc = (ObjectStreamClass)classDescStack.pop()) != null);
} finally {
classDescStack.setSize(stackMark);
}
}
}
/* Serialize the reference if it is NULL or is for an object that
* was already replaced or already serialized.
* If the object was already replaced, look for the replacement
* object in the known objects and if found, write its handle
* Return True if the reference is either null or a repeat.
*/
private boolean serializeNullAndRepeat(Object obj)
throws IOException
{
if (obj == null) {
writeCode(TC_NULL);
return true;
}
/* Look to see if this object has already been replaced.
* If so, proceed using the replacement object.
*/
if (replaceObjects != null) {
for (int i = 0; i < nextReplaceOffset; i+= 2) {
if (replaceObjects[i] == obj) {
obj = replaceObjects[i+1];
break;
}
}
}
int handle = findWireOffset(obj);
if (handle >= 0) {
/* Add a reference to the stream */
writeCode(TC_REFERENCE);
writeInt(handle + baseWireHandle);
return true;
}
return false; // not serialized, its up to the caller
}
/*
* Locate and return if found the handle for the specified object.
* -1 is returned if the object does not occur in the array of
* known objects.
*/
private int findWireOffset(Object obj) {
int hash = System.identityHashCode(obj);
int index = (hash & 0x7FFFFFFF) % wireHash2Handle.length;
for (int handle = wireHash2Handle[index];
handle >= 0;
handle = wireNextHandle[handle]) {
if (wireHandle2Object[handle] == obj)
return handle;
}
return -1;
}
/* Allocate a handle for an object.
* The Vector is indexed by the wireHandleOffset
* and contains the object.
*/
private void assignWireOffset(Object obj)
throws IOException
{
// Extend the array if there isn't room for this new element
if (nextWireOffset == wireHandle2Object.length) {
Object[] oldhandles = wireHandle2Object;
wireHandle2Object = new Object[nextWireOffset*2];
System.arraycopy(oldhandles, 0,
wireHandle2Object, 0,
nextWireOffset);
int[] oldnexthandles = wireNextHandle;
wireNextHandle = new int[nextWireOffset*2];
System.arraycopy(oldnexthandles, 0,
wireNextHandle, 0,
nextWireOffset);
// TBD: Rehash the hash array if necessary
}
wireHandle2Object[nextWireOffset] = obj;
hashInsert(obj, nextWireOffset);
nextWireOffset++;
return;
}
/*
* Insert the specified object into the hash array and link if
* necessary. Put the new object into the hash table and link the
* previous to it. Newer objects occur earlier in the list.
*/
private void hashInsert(Object obj, int offset) {
int hash = System.identityHashCode(obj);
int index = (hash & 0x7FFFFFFF) % wireHash2Handle.length;
wireNextHandle[offset] = wireHash2Handle[index];
wireHash2Handle[index] = offset;
}
/*
* Add a replacement object to the table.
* The even numbered indices are the original objects.
* The odd numbered indices are the replacement objects.
*
*/
private void addReplacement(Object orig, Object replacement) {
// Extend the array if there isn't room for this new element
if (replaceObjects == null) {
replaceObjects = new Object[10];
}
if (nextReplaceOffset == replaceObjects.length) {
Object[] oldhandles = replaceObjects;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?