objectstreamclass.java
来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 859 行 · 第 1/2 页
JAVA
859 行
ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
long h = 0;
try {
MessageDigest md = MessageDigest.getInstance("SHA");
DigestOutputStream mdo = new DigestOutputStream(devnull, md);
DataOutputStream data = new DataOutputStream(mdo);
data.writeUTF(thisclass.getName());
int classaccess = getClassAccess(thisclass);
classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
Modifier.INTERFACE | Modifier.ABSTRACT);
data.writeInt(classaccess);
/*
* Get the list of interfaces supported,
* Accumulate their names their names in Lexical order
* and add them to the hash
*/
Class interfaces[] = thisclass.getInterfaces();
quicksort(interfaces);
for (int i = 0; i < interfaces.length; i++) {
data.writeUTF(interfaces[i].getName());
}
/* Sort the field names to get a deterministic order */
String fields[] = getFieldSignatures(thisclass);
quicksort(fields);
/* Include in the hash all fields except those that are
* private transient and private static.
*/
for (int i = 0; i < fields.length; i++) {
String field = fields[i];
int access = getFieldAccess(thisclass, field);
if ((access & M_PRIVATE) == M_PRIVATE &&
(((access & M_TRANSIENT) == M_TRANSIENT)||
((access & M_STATIC) == M_STATIC)))
continue;
int offset = field.indexOf(' ');
String name = field.substring(0, offset);
String desc = field.substring(offset+1);
data.writeUTF(name);
data.writeInt(access);
data.writeUTF(desc);
}
/*
* Get the list of methods including name and signature
* Sort lexically, add all except the private methods
* to the hash with their access flags
*/
String methods[] = getMethodSignatures(thisclass);
quicksort(methods);
for (int i = 0; i < methods.length; i++) {
String method = methods[i];
int access = getMethodAccess(thisclass, method);
if ((access & M_PRIVATE) != 0)
continue;
int offset = method.indexOf(' ');
String mname = method.substring(0, offset);
String desc = method.substring(offset+1);
desc = desc.replace('/', '.');
data.writeUTF(mname);
data.writeInt(access);
data.writeUTF(desc);
}
/* Compute the hash value for this class.
* Use only the first 64 bits of the hash.
*/
byte hasharray[] = md.digest();
for (int i = 0; i < Math.min(8, hasharray.length); i++) {
h += (long)(hasharray[i] & 255) << (i * 8);
}
} catch (IOException ignore) {
/* can't happen, but be deterministic anyway. */
h = -1;
} catch (NoSuchAlgorithmException complain) {
throw new SecurityException(complain.getMessage());
}
return h;
}
/* These are in this class so that there is no chance they can be used
* outside the class.
*/
private static native int getClassAccess(Class aclass);
private static native String[] getMethodSignatures(Class aclass);
private static native int getMethodAccess(Class aclass, String methodsig);
private static native String[] getFieldSignatures(Class aclass);
private static native int getFieldAccess(Class aclass, String fieldsig);
private static final int M_TRANSIENT = 0x0080;
private static final int M_PRIVATE = 0x0002;
private static final int M_STATIC = 0x0008;
/*
* locate the ObjectStreamClass for this class and write it to the stream.
*/
void write(ObjectOutputStream s) throws IOException {
/* write the flag indicating that this class has write/read object methods */
int flags = 0;
if (hasWriteObjectMethod)
flags |= ObjectStreamConstants.SC_WRITE_METHOD;
if (serializable)
flags |= ObjectStreamConstants.SC_SERIALIZABLE;
if (externalizable)
flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
s.writeByte(flags);
/* write the total number of fields */
s.writeShort(fields.length);
/* Write out the descriptors of the primitive fields Each
* descriptor consists of the UTF fieldname, a short for the
* access modes, and the first byte of the signature byte.
* For the object types, ('[' and 'L'), a reference to the
* type of the field follows.
*/
/* disable replacement of String objects written
* by ObjectStreamClass. */
boolean prevReplaceObject = s.enableReplace;
s.enableReplace = false;
try {
for (int i = 0; i < fields.length; i++ ) {
ObjectStreamField f = fields[i];
s.writeByte(f.type);
s.writeUTF(f.name);
if (!f.isPrimitive()) {
s.writeObject(f.typeString);
}
}
} finally {
s.enableReplace = prevReplaceObject;
}
}
/*
* Read the version descriptor from the stream.
* Write the count of field descriptors
* for each descriptor write the first character of its type,
* the name of the field.
* If the type is for an object either array or object, write
* the type typedescriptor for the type
*/
void read(ObjectInputStream s) throws IOException, ClassNotFoundException {
/* read flags and determine whether the source class had
* write/read methods.
*/
byte flags = s.readByte();
serializable = (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
externalizable = (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
hasWriteObjectMethod = serializable ?
(flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0 :
false;
/* MOVED from ObjectStreamConstants, due to failing SignatureTest.
* In JDK 1.2, SC_BLOCK_DATA is a constant in ObjectStreamConstants.
* If SC_EXTERNALIZABLE, this bit indicates externalizable data
* written in block data mode. */
final byte SC_BLOCK_DATA = 0x08;
hasExternalizableBlockData = externalizable ?
(flags & SC_BLOCK_DATA) != 0 :
false;
/* Read the number of fields described.
* For each field read the type byte, the name.
*/
int count = s.readShort();
fields = new ObjectStreamField[count];
/* disable replacement of String objects written
* by ObjectStreamClass. */
boolean prevEnableResolve = s.enableResolve;
s.enableResolve = false;
try {
for (int i = 0; i < count; i++ ) {
char type = (char)s.readByte();
String name = s.readUTF();
String ftype = null;
if (type == '[' || type == 'L') {
ftype = (String)s.readObject();
}
fields[i] = new ObjectStreamField(name, type, -1, ftype);
}
} finally {
s.enableResolve = prevEnableResolve;
}
}
/*
* Cache of Class -> ClassDescriptor Mappings.
*/
static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
/*
* findDescriptorFor a Class.
* This looks in the cache for a mapping from Class -> ObjectStreamClass mappings.
* The hashCode of the Class is used for the lookup since the Class is the key.
* The entries are extended from sun.misc.Ref so the gc will be able to free them
* if needed.
*/
private static ObjectStreamClass findDescriptorFor(Class cl) {
int hash = cl.hashCode();
int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
ObjectStreamClassEntry e;
ObjectStreamClassEntry prev;
/* Free any initial entries whose refs have been cleared */
while ((e = descriptorFor[index]) != null && e.check() == null) {
descriptorFor[index] = e.next;
}
/* Traverse the chain looking for a descriptor with ofClass == cl.
* unlink entries that are unresolved.
*/
prev = e;
while (e != null ) {
ObjectStreamClass desc = (ObjectStreamClass)(e.check());
if (desc == null) {
// This entry has been cleared, unlink it
prev.next = e.next;
} else {
if (desc.ofClass == cl)
return desc;
prev = e;
}
e = e.next;
}
return null;
}
/*
* insertDescriptorFor a Class -> ObjectStreamClass mapping.
*/
private static void insertDescriptorFor(ObjectStreamClass desc) {
// Make sure not already present
if (findDescriptorFor(desc.ofClass) != null) {
return;
}
int hash = desc.ofClass.hashCode();
int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
ObjectStreamClassEntry e = new ObjectStreamClassEntry();
e.setThing(desc);
e.next = descriptorFor[index];
descriptorFor[index] = e;
}
/*
* The name of this descriptor
*/
private String name;
/*
* The descriptor of the supertype.
*/
private ObjectStreamClass superclass;
/*
* Flags for Serializable and Externalizable.
*/
private boolean serializable;
private boolean externalizable;
/*
* Array of persistent fields of this class, sorted by
* type and name.
*/
private ObjectStreamField[] fields;
/*
* Class that is a descriptor for in this virtual machine.
*/
private Class ofClass;
/*
* SerialVersionUID for this class.
*/
private long suid;
/*
* This sequence of type, byte offset of the fields to be
* serialized and deserialized.
*/
private int[] fieldSequence;
/* True if this class has/had a writeObject method */
private boolean hasWriteObjectMethod;
/* In JDK 1.1, external data was not written in block mode.
* As of JDK 1.2, external data is written in block data mode. This
* flag enables JDK 1.1.6 to distinguish between JDK 1.1 external
* data format and JDK 1.2 external data format.
*
* @since JDK 1.1.6
*/
private boolean hasExternalizableBlockData;
/*
* ObjectStreamClass that this one was built from.
*/
private ObjectStreamClass localClassDesc;
/* Get the array of non-static and non-transient fields */
private native ObjectStreamField[] getFields0(Class cl);
/* Get the serialVersionUID from the specified class */
private static native long getSerialVersionUID(Class cl);
/* Get the boolean as to whether the class has/had a writeObject method. */
private static native boolean hasWriteObject(Class cl);
/* The Class Object for java.io.Serializable */
private static Class classSerializable = null;
private static Class classExternalizable = null;
/*
* Resolve java.io.Serializable at load time.
*/
static {
try {
classSerializable = Class.forName("java.io.Serializable");
classExternalizable = Class.forName("java.io.Externalizable");
} catch (Throwable e) {
System.err.println("Could not load java.io.Serializable or java.io.Externalizable.");
}
}
/* Support for quicksort */
/*
* Implement the doCompare method.
* Strings are compared directly.
* Classes are compared using their names.
* ObjectStreamField objects are compared by type and name
* and then their descriptors (as strings).
*/
private static int doCompare(Object o1, Object o2) {
String s1, s2;
if (o1 instanceof String && o2 instanceof String) {
s1 = (String)o1;
s2 = (String)o2;
} else if (o1 instanceof Class && o2 instanceof Class) {
Class c1 = (Class)o1;
Class c2 = (Class)o2;
s1 = c1.getName();
s2 = c2.getName();
} else if (o1 instanceof ObjectStreamField &&
o2 instanceof ObjectStreamField) {
ObjectStreamField f1 = (ObjectStreamField)o1;
ObjectStreamField f2 = (ObjectStreamField)o2;
s1 = f1.name;
s2 = f2.name;
} else {
throw new Error("Unsupported types");
}
return s1.compareTo(s2);
}
private static void swap(Object arr[], int i, int j) {
Object tmp;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
/*
* quicksort the array of objects.
*
* @param arr[] - an array of objects
* @param left - the start index - from where to begin sorting
* @param right - the last index.
*/
private static void quicksort(Object arr[], int left, int right)
{
int i, last;
if (left >= right) { /* do nothing if array contains fewer than two */
return; /* two elements */
}
swap(arr, left, (left+right) / 2);
last = left;
for (i = left+1; i <= right; i++) {
if (doCompare(arr[i], arr[left]) < 0) {
swap(arr, ++last, i);
}
}
swap(arr, left, last);
quicksort(arr, left, last-1);
quicksort(arr, last+1, right);
}
/*
* Preform a sort using the specified comparitor object.
*/
private static void quicksort(Object arr[]) {
quicksort(arr, 0, arr.length-1);
}
}
/*
* Entries held in the Cache of known ObjectStreamClass objects.
* Entries are chained together with the same hash value (modulo array size).
*/
class ObjectStreamClassEntry extends sun.misc.Ref {
ObjectStreamClassEntry next;
public Object reconstitute() {
return null;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?