Java I/O 23 - ObjectInputStream

  关于 java.io.ObjectInputStream 的部分笔记,ObjectInputStream是Java反序列化操作的实现类,通过该类可以完成默认的或者自定义的对象反序列化操作。本文演示代码段的执行环境基于JDK版本1.7

概述

  ObjectInputStream对来自于ObjectOutputStream的基础数据类型和对象数据做反序列化操作。ObjectInputStream和ObjectOutputStream被用于持久化存储对象数据(只有支持java.io.Serializablejava.io.Externalizable的对象才会拥有这个能力)的场景中。java.io.Serializablejava.io.Externalizable这两个接口决定了序列化和反序列化的执行过程。用来将数据序列化处理之后通过网络等途径传输到目标持久化位置,而ObjectInputStream则会将序列化之后的数据反序列之后传入内存中供计算机程序处理,保证了从流中得到的对象还原成JVM支持的数据类型。

  ObjectInputStream中的readObject()方法会从流中读取被序列化的对象数据。基础数据类型可以通过readXX()方法得到。默认的反序列化机制会计算并返回对象的每个字段被序列化之前的类型和存储的内容。如果字段声明中含有transient或者static,那么这些字段在反序列化的过程中不会被恢复。如果在一个对象中引用了其他对象,那么这些被引用的对象也会被序列化且ObjectInputStream会从流中尝试反序列这些对象。在反序列化的过程中,新的对象和原有对象分别占用不同的内存空间,所以对原有对象的修改不会影响到新对象,反之亦然。

  前面说过共有两个接口来标识可序列化的类:java.io.Serializable和java.io.Externalizable。实现了java.io.Serializable接口的对象可以被对象序列化机制自动地存储和恢复类的所有内容和状态,并且允许类在对象被写入流和从流中读取的时间段内发生变化。如果说某个实现了java.io.Serializable接口的类需要自定义序列化和反序列操作,那么就需要实现readObjectNoData()writeObject(java.io.ObjectOutputStream stream)readObject(java.io.ObjectInputStream stream)方法。readObject方法负责从流中读取数据并且恢复类的各个状态,恢复的基础是依据通过对应的writeObject方法向流中写入的对象已经被序列化了的数据内容。被反序列之后的新对象通过从ObjectInputStream中读取数据并且完成对象中各个字段的赋值操作。如果在读书序列化数据执行反序列操作时数据读取越界,那么就会抛出一个OptionalDataException异常。

  序列化操作不会对没有实现Serializable接口的对象进行操作,如果父类没有序列化,那么其子类依旧可以做序列化操作,这种情况下子类需要对没有不支持序列化的父类的保存和还原负责,这时需要父类的字段属性的权限类型是public, package, 或者protected,以及提供用来还原字段内容的get/set方法。

继承关系

1
2
3
4
// ObjectInputStream
--java.lang.Object
--java.io.InputStream
--java.io.ObjectInputStream

实现接口

类名 实现接口
ObjectInputStream Closeable, DataInput, ObjectInput, ObjectStreamConstants, AutoCloseable

ObjectInputStream

Constructor Summary

public ObjectInputStream(InputStream in)

1
2
3
4
5
6
7
8
9
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
enableOverride = false;
readStreamHeader();
bin.setBlockDataMode(true);
}

  根据指定输入流初始化一个ObjectInputStream实例。在过程中会从流中读取一个序列化流头部信息,如果序列化尚未将流头部信息写入到流中那么该过程会阻塞。之后会执行security manager。

如果有子类继承了当前ObjectInputStream,那么verifySubclass()方法需要检查子类是否违反安全限制:子类不能覆盖安全敏感的非final方法,否则将执行“支持子类实现”的序列化准许(”enableSubclassImplementation” SerializablePermission)检查。

  之后初始化一个BlockDataInputStream完成数据读取。调用readStreamHeader()完成流头部信息读取操作。如果流头部信息不正确,抛出StreamCorruptedException异常,如果在读取流头部过程中发生I/O异常,那么抛出IOException

protected ObjectInputStream()

1
2
3
4
5
6
7
8
9
10
protected ObjectInputStream() throws IOException, SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
bin = null;
handles = null;
vlist = null;
enableOverride = true;
}

  为子类提供了一种可以完全重新实现ObjectInputStream的途径,这个方法不需要再单独分配私有字段而直接使用ObjectInputStream中的字段。如果存在security manager,那么首先需要调用checkPermission(Permission perm)完成检查,保证“支持子类实现”的序列化准许(”enableSubclassImplementation” SerializablePermission)检查适用于子类。

部分方法

private void verifySubclass()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void verifySubclass() {
Class cl = getClass();
if (cl == ObjectInputStream.class) {
return;
}
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
return;
}
processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
Boolean result = Caches.subclassAudits.get(key);
if (result == null) {
result = Boolean.valueOf(auditSubclass(cl));
Caches.subclassAudits.putIfAbsent(key, result);
}
if (result.booleanValue()) {
return;
}
sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}

  检查子类是否违反安全限制:子类不能覆盖安全敏感的非final方法,否则将执行“支持子类实现”的序列化准许(”enableSubclassImplementation” SerializablePermission)检查。或者说,该方法会检查当前需要构造的类是不是ObjectInputStream自身或者其子类。

  第2 ~ 5行代码获取当前运行的类,如果是ObjectInputStream自身,那么直接返回。第6 ~ 9行代码判断是否带有SecurityManager,如果没有直接返回。第10行代码通过如下方法移除Caches中已经失去引用的class对象:

1
2
processQueue(ReferenceQueue<Class<?>> queue,
ConcurrentMap<? extends WeakReference<Class<?>>, ?> map)

  第11行代码通过初始化一个弱引用将ObjectInputStream的子类存入Caches中。在第14行代码中检查当前子类是否覆盖了安全敏感的非final方法,如果是安全的(检查通过了),那么返回true,否则返回false标识检查未通过。然后在15行代码中将当前ObjectInputStream子类维护到Caches的subclassAudits集合中。

  最后第20行代码完成当前实现类是否拥有SUBCLASS_IMPLEMENTATION_PERMISSION权限,如果没有,则需要抛出SecurityException异常。

private static boolean auditSubclass(final Class<?> subcl)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private static boolean auditSubclass(final Class<?> subcl) {
Boolean result = AccessController.doPrivileged(
new PrivilegedAction<Boolean>() {
public Boolean run() {
for (Class<?> cl = subcl;
cl != ObjectInputStream.class;
cl = cl.getSuperclass())
{
try {
cl.getDeclaredMethod(
"readUnshared", (Class[]) null);
return Boolean.FALSE;
} catch (NoSuchMethodException ex) {
}
try {
cl.getDeclaredMethod("readFields", (Class[]) null);
return Boolean.FALSE;
} catch (NoSuchMethodException ex) {
}
}
return Boolean.TRUE;
}
}
);
return result.booleanValue();
}

  用来完成子类的安全检查。检查子类是否覆盖了安全敏感的非final方法,如果没有返回true表示检查通过,否则返回false。

  第5 ~ 8行代码从入参subc1自身开始,依次得到其直接父类,直到到达ObjectInputStream,检查每个类是否存在”readUnshared”和”readFields”方法,如果有,返回false,否则抛出NoSuchMethodException异常最后返回true表示检查通过。

protected void readStreamHeader()

1
2
3
4
5
6
7
8
protected void readStreamHeader() throws IOException, StreamCorruptedException {
short s0 = bin.readShort();
short s1 = bin.readShort();
if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
throw new StreamCorruptedException(
String.format("invalid stream header: %04X%04X", s0, s1));
}
}

  协助子类读取和验证它们自己的流头部,过程中会读取和校验魔数和版本号。这两个数都是序列化过程中写入到流里的。

public final Object readObject()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public final Object readObject() throws IOException, ClassNotFoundException {
if (enableOverride) {
return readObjectOverride();
}

// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
Object obj = readObject0(false);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
}
return obj;
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
}
}

  从ObjectInputStream中读取一个对象,final关键字表示该方法不可能被子类覆盖。对象的类型、类型签名、未被transient和static修饰的字段值以及该对象的所有父类型都会被读取到。对一个类对象的默认的反序列操作可通过readObject()和writeObject()方法覆盖以实现个性化需求。与该对象相关的所有对象都会被readObject()方法读取到以保证可以完整的完成反序列化。需要注意的是,只有当当前对象的所有字段以及其所有引用的其他对象都被恢复了以后,这个对象的反序列化过程才算完成。

  第2 ~ 4行代码如果需要使用子类实现来完成数据读取,那么就调用readObjectOverride()。enableOverride字段会在protected ObjectInputStream()构造器中被指定为true,而该构造器是给ObjectInputStream的子类初始化用的,所以如果是子类实现,那么就用子类的读取方法来完成数据读取操作。如果类里面定义了非基本数据类型变量,需要进行嵌套读取,outerHandle用来存储上一层读取对象的句柄,所以第7行代码维护了上一层读取对象的句柄。然后调用readObject0读取生成对象(整个方法的核心!核心!核心!)。完成之后要记录句柄依赖(第10行代码),并检查有无异常产生(第11行代码)。第15 ~ 17行代码表示最上层读取完成之后要发起回调,最后返回反序列的对象obj。

  第20 ~ 24行代码如果最上层调用结束后那么清空相关记录缓存(包含但不限于调用返回列表和句柄缓存)。

protected Object readObjectOverride()

1
2
3
4
protected Object readObjectOverride() throws IOException, ClassNotFoundException
{
return null;
}

  ObjectInputStream的子类覆盖该方法以完成子类的反序列的操作。留给子类用的,ObjectInputStream自身无法使用该方法。

private Object readObject0(boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
private Object readObject0(boolean unshared) throws IOException {
boolean oldMode = bin.getBlockDataMode();
if (oldMode) {
int remain = bin.currentBlockRemaining();
if (remain > 0) {
throw new OptionalDataException(remain);
} else if (defaultDataEnd) {
/*
* Fix for 4360508: stream is currently at the end of a field
* value block written via default serialization; since there
* is no terminating TC_ENDBLOCKDATA tag, simulate
* end-of-custom-data behavior explicitly.
*/
throw new OptionalDataException(true);
}
bin.setBlockDataMode(false);
}

byte tc;
while ((tc = bin.peekByte()) == TC_RESET) {
bin.readByte();
handleReset();
}

depth++;
try {
switch (tc) {
case TC_NULL:
return readNull();

case TC_REFERENCE:
return readHandle(unshared);

case TC_CLASS:
return readClass(unshared);

case TC_CLASSDESC:
case TC_PROXYCLASSDESC:
return readClassDesc(unshared);

case TC_STRING:
case TC_LONGSTRING:
return checkResolve(readString(unshared));

case TC_ARRAY:
return checkResolve(readArray(unshared));

case TC_ENUM:
return checkResolve(readEnum(unshared));

case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));

case TC_EXCEPTION:
IOException ex = readFatalException();
throw new WriteAbortedException("writing aborted", ex);

case TC_BLOCKDATA:
case TC_BLOCKDATALONG:
if (oldMode) {
bin.setBlockDataMode(true);
bin.peek(); // force header read
throw new OptionalDataException(
bin.currentBlockRemaining());
} else {
throw new StreamCorruptedException(
"unexpected block data");
}

case TC_ENDBLOCKDATA:
if (oldMode) {
throw new OptionalDataException(true);
} else {
throw new StreamCorruptedException(
"unexpected end of block data");
}

default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
} finally {
depth--;
bin.setBlockDataMode(oldMode);
}
}

  readObject0必须在上一次反序列化操作彻底完成后(此时流内不存在任何数据)才能开始当前的读取和反序列化操作,否则会抛出异常。

  第2 ~ 17行代码用来判断当前操作开始前流内是否存在上次反序列操作未处理的剩余数据,如果有,那么就抛出OptionalDataException异常。判断操作都执行完后执行bin.setBlockDataMode(false)标记本次读取和反序列操作开始。

  第19 ~ 23行代码中,如果读取的下一个字节是“TC_RESET”,那么意味着所有写入到流中的数据都会被重置。所以读取一个字节内容,然后调用handleReset()完成重置操作。

  第25行代码表示每调用一次readObject0方法,嵌套深度加一。

  之后根据读取到的tc码来分场景反序列恢复数据内容:

  1. 第28 ~ 30行代码表示如果恢复的是一个null元素引用,那么调用readNull()完成处理。
  2. 第31 ~ 33行代码表示如果恢复的是一个指向已经写入到流里的对象的引用,那么调用readHandle(boolean unshared)读取引用对象完成处理。
  3. 第34 ~ 36行代码表示如果恢复的是一个指向类的引用,那么调用readClass(boolean unshared)读取一个类完成处理。
  4. 第37 ~ 40行代码表示如果恢复的是一个指向类描述符或者代理类描述符的引用,那么调用readClassDesc(boolean unshared)读取一个类描述符完成处理。
  5. 第41 ~ 44行代码表示如果恢复的是一个String 或者long String(Unicode>0xFF),那么调用checkResolve(Object obj)检查readString(boolean unshared)的返回内容。
  6. 第45 ~ 47行代码表示如果恢复的是一个数组,那么调用checkResolve(Object obj)检查readArray(boolean unshared)的返回内容。
  7. 第48 ~ 50行代码表示如果恢复的是一个枚举常量,那么调用checkResolve(Object obj)检查readEnum(boolean unshared)的返回内容。
  8. 第51 ~ 53行代码表示如果恢复的是一个Object,那么调用checkResolve(Object obj)检查readOrdinaryObject(boolean unshared)的返回内容。
  9. 第54 ~ 57行代码表示如果恢复的是一个写入过程中产生的异常,那么调用readFatalException()获取异常内容。
  10. 第58 ~ 69行代码表示如果恢复的是一个块数据,那么抛出异常内容。
  11. 第70 ~ 77行代码表示如果恢复的是一个块数据结束标志,那么抛出异常内容。

  如果都不符合上述十一个场景,那么抛出异常。最后将深度减一表示当前层次处理已经完成。

private void handleReset()

1
2
3
4
5
6
7
private void handleReset() throws StreamCorruptedException {
if (depth > 0) {
throw new StreamCorruptedException(
"unexpected reset; recursion depth: " + depth);
}
clear();
}

  如果发生了嵌套读取反序列操作,且当前操作不处于最顶层,那么抛出StreamCorruptedException异常。如果处于最顶层,则调用clear()方法完成内部数据结构的清空操作。

private void clear()

1
2
3
4
private void clear() {
handles.clear();
vlist.clear();
}

  清空并使得句柄HandleTable处于初始态。清空并使得回调列表ValidationList处于初始态。

private Object readNull()

1
2
3
4
5
6
7
private Object readNull() throws IOException {
if (bin.readByte() != TC_NULL) {
throw new InternalError();
}
passHandle = NULL_HANDLE;
return null;
}

  这个方法处理的读取到的元素是null的场景,如果实际读到的不是null,那么抛出异常。反之,由于passHandle维护的是一个对象句柄,而此方法读取并返回的是一个null,所以句柄被置为null并返回null。

private Object readHandle(boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private Object readHandle(boolean unshared) throws IOException {
if (bin.readByte() != TC_REFERENCE) {
throw new InternalError();
}
passHandle = bin.readInt() - baseWireHandle;
if (passHandle < 0 || passHandle >= handles.size()) {
throw new StreamCorruptedException(
String.format("invalid handle value: %08X", passHandle +
baseWireHandle));
}
if (unshared) {
// REMIND: what type of exception to throw here?
throw new InvalidObjectException(
"cannot read back reference as unshared");
}

Object obj = handles.lookupObject(passHandle);
if (obj == unsharedMarker) {
// REMIND: what type of exception to throw here?
throw new InvalidObjectException(
"cannot read back reference to unshared object");
}
return obj;
}

  从流里读取到一个对象句柄,将passHandle置为读取到的这个句柄,并返回一个关联到该句柄上的对象。如果当前读到的不是一个REFERENCE标识,那么抛出异常。因为在向流写入的过程中数据等于handle值加baseWireHandle的和,所以这里要减去还原。由于元素handle值在写入时是逐个增加的(实际上在写入过程中是依据写入环境的handle集合存储的元素个数作为handle存储的index下标的,最终实现效果就是在尾部加入元素)所以passHandle值不可能大于handles的长度,如果不满条件,那么抛出异常。

  如果unshared为true,抛出异常。从缓存中寻找并取出对象。如果找到的对象带有unshared标记,抛出异常。反之向方法调用方返回找到的对象。

private Class readClass(boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private Class readClass(boolean unshared) throws IOException {
if (bin.readByte() != TC_CLASS) {
throw new InternalError();
}
ObjectStreamClass desc = readClassDesc(false);
Class cl = desc.forClass();
passHandle = handles.assign(unshared ? unsharedMarker : cl);

ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}

handles.finish(passHandle);
return cl;
}

  从流里读取并返回一个类对象,将passHandle置为类对象分配的句柄。如果类无法被解析(ClassNotFoundException会被关联到类的句柄上),那么返回null。

  如果当前读到的不是一个TC_CLASS标识,那么抛出异常。紧接着读取并返回一个类描述符。如果得到的类描述符无法正常解析出一个可以在本地VM运行的类,那么抛出异常。从返回的类描述符中返回一个来自于本地VM的类。然后根据unshared标记决定passHandle是指向一个unsharedMarker还是刚才得到的类。

  第9行代码检查在解析本地类的过程中是否出现了异常,如果有异常,需要将当前passHandle与异常建立映射关系。结束当前passHandle的映射建立过程,该passHandle将不会与其他新的对象建立映射关系。最后返回得到的类。

private ObjectStreamClass readClassDesc(boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private ObjectStreamClass readClassDesc(boolean unshared) throws IOException {
byte tc = bin.peekByte();
switch (tc) {
case TC_NULL:
return (ObjectStreamClass) readNull();

case TC_REFERENCE:
return (ObjectStreamClass) readHandle(unshared);

case TC_PROXYCLASSDESC:
return readProxyDesc(unshared);

case TC_CLASSDESC:
return readNonProxyDesc(unshared);

default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
}

  读取并返回一个类描述符。将passHandle分给类描述符指定的句柄。如果类描述符无法正确解析成一个本地VM中的一个类,那么抛出ClassNotFoundException异常。

  读取TC标识,如果TC标识为TC_NULL,那么调用readNull()返回一个null对象。

  如果TC标识为TC_REFERENCE,那么调用readHandle(boolean unshared)返回一个句柄指向的对象。

  如果TC标识为TC_PROXYCLASSDESC,那么调用readProxyDesc(boolean unshared)返回一个动态代理类的类描述符。

  如果TC标识为TC_CLASSDESC,那么调用readNonProxyDesc(boolean unshared)返回一个非动态代理类的类描述符。

  如果不是上述场景,抛出异常。

private ObjectStreamClass readProxyDesc(boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private ObjectStreamClass readProxyDesc(boolean unshared) throws IOException {
if (bin.readByte() != TC_PROXYCLASSDESC) {
throw new InternalError();
}

ObjectStreamClass desc = new ObjectStreamClass();
int descHandle = handles.assign(unshared ? unsharedMarker : desc);
passHandle = NULL_HANDLE;

int numIfaces = bin.readInt();
String[] ifaces = new String[numIfaces];
for (int i = 0; i < numIfaces; i++) {
ifaces[i] = bin.readUTF();
}

Class cl = null;
ClassNotFoundException resolveEx = null;
bin.setBlockDataMode(true);
try {
if ((cl = resolveProxyClass(ifaces)) == null) {
resolveEx = new ClassNotFoundException("null class");
} else if (!Proxy.isProxyClass(cl)) {
throw new InvalidClassException("Not a proxy");
} else {
// ReflectUtil.checkProxyPackageAccess makes a test
// equivalent to isCustomSubclass so there's no need
// to condition this call to isCustomSubclass == true here.
ReflectUtil.checkProxyPackageAccess(getClass().getClassLoader(),
cl.getInterfaces());
}
} catch (ClassNotFoundException ex) {
resolveEx = ex;
}
skipCustomData();

desc.initProxy(cl, resolveEx, readClassDesc(false));

handles.finish(descHandle);
passHandle = descHandle;
return desc;
}

  读取并返回一个动态代理类的类描述符。如果当前读到的不是一个TC_PROXYCLASSDESC标识,那么抛出异常。第6行代码用来初始化一个空的类描述符,该描述符包含有类描述符的名字和serialVersionUID。第10 ~ 15行代码获取动态代理类实现的接口内容。第20 ~ 21行代码试图返回一个实现了相关接口的动态代理类,如果返回失败,那么抛出异常。如果返回的不是动态代理类,那么抛出异常。紧接着利用类描述符初始化一个动态代理类,更新passHandle的值并返回初始化的动态代理类。

protected Class<?> resolveProxyClass(String[] interfaces)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
protected Class<?> resolveProxyClass(String[] interfaces)
throws IOException, ClassNotFoundException {
ClassLoader latestLoader = latestUserDefinedLoader();
ClassLoader nonPublicLoader = null;
boolean hasNonPublicInterface = false;

// define proxy in class loader of non-public interface(s), if any
Class[] classObjs = new Class[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
Class cl = Class.forName(interfaces[i], false, latestLoader);
if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
if (hasNonPublicInterface) {
if (nonPublicLoader != cl.getClassLoader()) {
throw new IllegalAccessError(
"conflicting non-public interface class loaders");
}
} else {
nonPublicLoader = cl.getClassLoader();
hasNonPublicInterface = true;
}
}
classObjs[i] = cl;
}
try {
return Proxy.getProxyClass(
hasNonPublicInterface ? nonPublicLoader : latestLoader, classObjs);
} catch (IllegalArgumentException e) {
throw new ClassNotFoundException(null, e);
}
}

  返回一个实现了代理类描述符中包含的所有接口的代理类。ObjectInputStream的子类可以实现这个方法来满足个性化的数据内容的读取需求,为开发人员提供了一种可供选择的接口和代理类的加载机制。第8 ~ 23行代码遍历每个接口信息,根据接口和得到的类加载器生成对应的实现类。如果生成的类是public修饰的,那么判断是否拥有非公共的类加载器。最后从生成的类对象中得到生成的代理类。

private static ClassLoader latestUserDefinedLoader()

1
2
3
private static ClassLoader latestUserDefinedLoader() {
return sun.misc.VM.latestUserDefinedLoader();
}

  返回第一个非null的类加载器到执行栈。

private void skipCustomData()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private void skipCustomData() throws IOException {
int oldHandle = passHandle;
for (;;) {
if (bin.getBlockDataMode()) {
bin.skipBlockData();
bin.setBlockDataMode(false);
}
switch (bin.peekByte()) {
case TC_BLOCKDATA:
case TC_BLOCKDATALONG:
bin.setBlockDataMode(true);
break;

case TC_ENDBLOCKDATA:
bin.readByte();
passHandle = oldHandle;
return;

default:
readObject0(false);
break;
}
}
}

  跳过所有的块数据和对象直到遇到TC_ENDBLOCKDATA。

private ObjectStreamClass readNonProxyDesc(boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private ObjectStreamClass readNonProxyDesc(boolean unshared) throws IOException {
if (bin.readByte() != TC_CLASSDESC) {
throw new InternalError();
}

ObjectStreamClass desc = new ObjectStreamClass();
int descHandle = handles.assign(unshared ? unsharedMarker : desc);
passHandle = NULL_HANDLE;

ObjectStreamClass readDesc = null;
try {
readDesc = readClassDescriptor();
} catch (ClassNotFoundException ex) {
throw (IOException) new InvalidClassException(
"failed to read class descriptor").initCause(ex);
}

Class cl = null;
ClassNotFoundException resolveEx = null;
bin.setBlockDataMode(true);
final boolean checksRequired = isCustomSubclass();
try {
if ((cl = resolveClass(readDesc)) == null) {
resolveEx = new ClassNotFoundException("null class");
} else if (checksRequired) {
ReflectUtil.checkPackageAccess(cl);
}
} catch (ClassNotFoundException ex) {
resolveEx = ex;
}
skipCustomData();

desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));

handles.finish(descHandle);
passHandle = descHandle;
return desc;
}

  读取并返回一个不是动态代理类的类描述符。如果当前读到的不是一个TC_CLASSDESC标识,那么抛出异常。第6行代码生成一个类描述符实例,里面含有类名和接口名。第10 ~ 16行代码会从序列化流中读取一个类描述符。第21行代码判断当前类是否是ObjectInputStream的子类实现。第22 ~ 30行代码异常检查。第33行代码会初始化一个非动态代理类,最后返回生成的类描述符。

protected ObjectStreamClass readClassDescriptor()

1
2
3
4
5
6
protected ObjectStreamClass readClassDescriptor()
throws IOException, ClassNotFoundException {
ObjectStreamClass desc = new ObjectStreamClass();
desc.readNonProxy(this);
return desc;
}

  从序列化流中读取一个类描述符。ObjectInputStream的子类可以覆盖这个方法以此实现可以以非标准化格式写入的类描述符。

protected Class<?> resolveClass(ObjectStreamClass desc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
String name = desc.getName();
try {
return Class.forName(name, false, latestUserDefinedLoader());
} catch (ClassNotFoundException ex) {
Class<?> cl = primClasses.get(name);
if (cl != null) {
return cl;
} else {
throw ex;
}
}
}

  加载本地的特定类描述符的类。

private Object checkResolve(Object obj)

1
2
3
4
5
6
7
8
9
10
private Object checkResolve(Object obj) throws IOException {
if (!enableResolve || handles.lookupException(passHandle) != null) {
return obj;
}
Object rep = resolveObject(obj);
if (rep != obj) {
handles.setObject(passHandle, rep);
}
return rep;
}

  在必要时执行对象替换。通过enableResolveObject(boolean enable)在初始化ObjectInputStream之后调用设置enableResolve的值。resolveObject(Object obj)方法没有对入参做任何处理,直接返回。第6 ~ 8行代码判断被替换后的对象是否和替换前一直,如果不一致,则用替换后的对象和passHandle建立映射关系,最后会直接返回被替换后的对象。

protected Object resolveObject(Object obj)

1
2
3
protected Object resolveObject(Object obj) throws IOException {
return obj;
}

  这个方法提供给被ObjectInputStream信任的子类在反序列化过程中完成对象替换。通过方法enableResolveObject(boolean enable)可以得到子类是否能被ObjectInputStream信任。这个方法在对象读取后readObject()方法前被调用处理。默认方法的话直接返回不做任何处理。

private IOException readFatalException()

1
2
3
4
5
6
7
private IOException readFatalException() throws IOException {
if (bin.readByte() != TC_EXCEPTION) {
throw new InternalError();
}
clear();
return (IOException) readObject0(false);
}

  读取并返回导致序列化操作取消的IOException。如果当前读到的不是一个TC_EXCEPTION标识,那么抛出异常。之后执行清空操作,清除所有内部数据结构。最后返回读取到的异常。

private String readString(boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private String readString(boolean unshared) throws IOException {
String str;
byte tc = bin.readByte();
switch (tc) {
case TC_STRING:
str = bin.readUTF();
break;

case TC_LONGSTRING:
str = bin.readLongUTF();
break;

default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
passHandle = handles.assign(unshared ? unsharedMarker : str);
handles.finish(passHandle);
return str;
}

  读取并返回一个String。根据读取到的TC标记选择readUTF()或者readLongUTF()方法完成字符串读取。TC_STRING和TC_LONGSTRING由对应的writeString确定,根据字符串Unicode值是否小于等于0xFFFF来决定写入TC_STRING(<= 0xFFFF)还是TC_LONGSTRING(> 0xFFFF)。如果不是上述两种标识,那么就抛出异常。

  然后建立passHandle句柄和读取到的字符串对象的映射关系。最后返回读取到的字符串。

private Object readArray(boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
private Object readArray(boolean unshared) throws IOException {
if (bin.readByte() != TC_ARRAY) {
throw new InternalError();
}

ObjectStreamClass desc = readClassDesc(false);
int len = bin.readInt();

Object array = null;
Class cl, ccl = null;
if ((cl = desc.forClass()) != null) {
ccl = cl.getComponentType();
array = Array.newInstance(ccl, len);
}

int arrayHandle = handles.assign(unshared ? unsharedMarker : array);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(arrayHandle, resolveEx);
}

if (ccl == null) {
for (int i = 0; i < len; i++) {
readObject0(false);
}
} else if (ccl.isPrimitive()) {
if (ccl == Integer.TYPE) {
bin.readInts((int[]) array, 0, len);
} else if (ccl == Byte.TYPE) {
bin.readFully((byte[]) array, 0, len, true);
} else if (ccl == Long.TYPE) {
bin.readLongs((long[]) array, 0, len);
} else if (ccl == Float.TYPE) {
bin.readFloats((float[]) array, 0, len);
} else if (ccl == Double.TYPE) {
bin.readDoubles((double[]) array, 0, len);
} else if (ccl == Short.TYPE) {
bin.readShorts((short[]) array, 0, len);
} else if (ccl == Character.TYPE) {
bin.readChars((char[]) array, 0, len);
} else if (ccl == Boolean.TYPE) {
bin.readBooleans((boolean[]) array, 0, len);
} else {
throw new InternalError();
}
} else {
Object[] oa = (Object[]) array;
for (int i = 0; i < len; i++) {
oa[i] = readObject0(false);
handles.markDependency(arrayHandle, passHandle);
}
}

handles.finish(arrayHandle);
passHandle = arrayHandle;
return array;
}

  读取并返回一个array数组。如果当前读到的不是一个TC_ARRAY标识,那么抛出异常。第6行代码得到数组类的类描述符,并读取数组的长度大小。第9 ~ 14行代码获取到数组的类型信息,以及数组元素的类型信息,通过Array.newInstance(Class<?> componentType, int length)方法初始化一个数组对象。

  第16 ~ 20行代码判断在当前写入和读取过程中是否出现了异常,如果有异常的话需要将passHandle和异常信息建立映射。第22 ~ 25行代码可能由于cl不是一个数组类,所以ccl为空,那么逐个获取长度为len的元素对象集合。如果数组元素类型为基本数据类型,那么就分类型从流中取数据填充到数组array中(即第26 ~ 45行代码)。如果数组元素为对象类型,那么递归调用readObject0()方法完成数组的填充。最后返回读取到的数据数据。

private Enum readEnum(boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private Enum readEnum(boolean unshared) throws IOException {
if (bin.readByte() != TC_ENUM) {
throw new InternalError();
}

ObjectStreamClass desc = readClassDesc(false);
if (!desc.isEnum()) {
throw new InvalidClassException("non-enum class: " + desc);
}

int enumHandle = handles.assign(unshared ? unsharedMarker : null);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(enumHandle, resolveEx);
}

String name = readString(false);
Enum en = null;
Class cl = desc.forClass();
if (cl != null) {
try {
en = Enum.valueOf(cl, name);
} catch (IllegalArgumentException ex) {
throw (IOException) new InvalidObjectException("enum constant "
+ name + " does not exist in " + cl).initCause(ex);
}
if (!unshared) {
handles.setObject(enumHandle, en);
}
}

handles.finish(enumHandle);
passHandle = enumHandle;
return en;
}

  读取并返回枚举常量。如果当前读到的不是一个TC_ENUM标识,那么抛出异常。通过readClassDesc(boolean unshared)方法获取到类描述符,如果类描述符不是枚举类型,那么抛出异常。之后检查在恢复本地类时是否出现了异常,如果有异常需要建立句柄和异常的映射关系。

  通过readString(boolean unshared)读取枚举类型的名字。然后在第22行代码会初始化一个Enum对象,之后更新passHandle的值并返回初始化的枚举对象。

private Object readOrdinaryObject(boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
private Object readOrdinaryObject(boolean unshared) throws IOException {
if (bin.readByte() != TC_OBJECT) {
throw new InternalError();
}

ObjectStreamClass desc = readClassDesc(false);
desc.checkDeserialize();

Class<?> cl = desc.forClass();
if (cl == String.class || cl == Class.class
|| cl == ObjectStreamClass.class) {
throw new InvalidClassException("invalid class descriptor");
}

Object obj;
try {
obj = desc.isInstantiable() ? desc.newInstance() : null;
} catch (Exception ex) {
throw (IOException) new InvalidClassException(desc.forClass()
.getName(), "unable to create instance").initCause(ex);
}

passHandle = handles.assign(unshared ? unsharedMarker : obj);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}

if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
}

handles.finish(passHandle);

if (obj != null && handles.lookupException(passHandle) == null
&& desc.hasReadResolveMethod()) {
Object rep = desc.invokeReadResolve(obj);
if (unshared && rep.getClass().isArray()) {
rep = cloneArray(rep);
}
if (rep != obj) {
handles.setObject(passHandle, obj = rep);
}
}

return obj;
}

  读取并返回一个自定义普通对象。如果对象类无法解析,返回一个null。如果当前读到的不是一个TC_OBJECT标识,那么抛出异常。调用readClassDesc(boolean unshared)方法完成类描述符的读取操作,如果该类被禁止反序列化,那么抛出InvalidClassException异常。第9 ~ 14行代码检查对象的类型,对象类型不应该为String,class,ObjectStreamClass等类,如果是的话就抛出异常。

  第15 ~21行代码实例化一个Object对象,如果对象可以实例化,就完成实例化,否则对象被指定为null。第23 ~ 27行代码检查在转换本地类的过程中是否存在异常,如果有异常需要对异常进行记录处理。如果对象继承的接口是Externalizable那么就调用readExternalData(Externalizable obj, ObjectStreamClass desc)完成操作,否则就调用readSerialData(Object obj, ObjectStreamClass desc)完成操作。

  如果当前已经实例化的对象存在替换对象,首先根据实例化的对象得到其对应的替换对象,如果替换对象的类型是数组,那么就执行数组克隆操作。用替换后的对象替换实例化对象并缓存起来。最后返回实例化的对象。

private static Object cloneArray(Object array)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private static Object cloneArray(Object array) {
if (array instanceof Object[]) {
return ((Object[]) array).clone();
} else if (array instanceof boolean[]) {
return ((boolean[]) array).clone();
} else if (array instanceof byte[]) {
return ((byte[]) array).clone();
} else if (array instanceof char[]) {
return ((char[]) array).clone();
} else if (array instanceof double[]) {
return ((double[]) array).clone();
} else if (array instanceof float[]) {
return ((float[]) array).clone();
} else if (array instanceof int[]) {
return ((int[]) array).clone();
} else if (array instanceof long[]) {
return ((long[]) array).clone();
} else if (array instanceof short[]) {
return ((short[]) array).clone();
} else {
throw new AssertionError();
}
}

  在使用非共享读取场景中克隆一个数组。

private void readExternalData(Externalizable obj, ObjectStreamClass desc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private void readExternalData(Externalizable obj, ObjectStreamClass desc)
throws IOException {
SerialCallbackContext oldContext = curContext;
curContext = null;
try {
boolean blocked = desc.hasBlockExternalData();
if (blocked) {
bin.setBlockDataMode(true);
}
if (obj != null) {
try {
obj.readExternal(this);
} catch (ClassNotFoundException ex) {
/*
* In most cases, the handle table has already propagated
* a CNFException to passHandle at this point; this mark
* call is included to address cases where the readExternal
* method has cons'ed and thrown a new CNFException of its
* own.
*/
handles.markException(passHandle, ex);
}
}
if (blocked) {
skipCustomData();
}
} finally {
curContext = oldContext;
}
/*
* At this point, if the externalizable data was not written in
* block-data form and either the externalizable class doesn't exist
* locally (i.e., obj == null) or readExternal() just threw a
* CNFException, then the stream is probably in an inconsistent state,
* since some (or all) of the externalizable data may not have been
* consumed. Since there's no "correct" action to take in this case,
* we mimic the behavior of past serialization implementations and
* blindly hope that the stream is in sync; if it isn't and additional
* externalizable data remains in the stream, a subsequent read will
* most likely throw a StreamCorruptedException.
*/
}

  如果obj非空,那么尝试通过readExternal()方法读取externalizable数据。

private void readSerialData(Object obj, ObjectStreamClass desc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
private void readSerialData(Object obj, ObjectStreamClass desc)
throws IOException {
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots[i].desc;

if (slots[i].hasData) {
if (obj != null &&
slotDesc.hasReadObjectMethod() &&
handles.lookupException(passHandle) == null)
{
SerialCallbackContext oldContext = curContext;

try {
curContext = new SerialCallbackContext(obj, slotDesc);

bin.setBlockDataMode(true);
slotDesc.invokeReadObject(obj, this);
} catch (ClassNotFoundException ex) {
/*
* In most cases, the handle table has already
* propagated a CNFException to passHandle at this
* point; this mark call is included to address cases
* where the custom readObject method has cons'ed and
* thrown a new CNFException of its own.
*/
handles.markException(passHandle, ex);
} finally {
curContext.setUsed();
curContext = oldContext;
}

/*
* defaultDataEnd may have been set indirectly by custom
* readObject() method when calling defaultReadObject() or
* readFields(); clear it to restore normal read behavior.
*/
defaultDataEnd = false;
} else {
defaultReadFields(obj, slotDesc);
}
if (slotDesc.hasWriteObjectData()) {
skipCustomData();
} else {
bin.setBlockDataMode(false);
}
} else {
if (obj != null &&
slotDesc.hasReadObjectNoDataMethod() &&
handles.lookupException(passHandle) == null)
{
slotDesc.invokeReadObjectNoData(obj);
}
}
}
}

  从流中读取每个实现了serializable接口的对象的实例化数据(从父类到子类全部)。第3行代码返回了类描述符desc指定的序列化的对象的数据层次(从父类开始)。遍历这些数据层次对象,如果obj有效,且数据层次有方法readObject且当前不存在异常,那么第18行代码就通过调用类的readObject方法来完成反序列化操作。如果数据层次无数据,那么第49行代码就通过调用类的readObjectNoData方法来完成反序列化操作。

public Object readUnshared()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public Object readUnshared() throws IOException, ClassNotFoundException {
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
Object obj = readObject0(true);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
}
return obj;
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
}
}

  从ObjectInputStream中读取含有私有类或者包内私有类的对象。这个方法被用在“保护不共享的反序列对象”场景中。如果一个类含有私有类的,或者包内私有类的对象引用字段,并且这些私有类或者包内私有类在当前类外(包外)不可用,那么这些引用对象需要作为反序列化过程的一部分来执行保护性复制(defensively copied)。或者通过调用ObjectOutputStream.writeUnshared 和ObjectInputStream.readUnshared保证内部对象的唯一引用。

  在复制策略中,从流中反序列化得到的子类被认为是不信任的输入 — 新创建的、反序列化之后拥有相同值的子对象应该被根据readObject方法得到的子对象替换掉。这么做是为了适应如下场景:一个不可变的对象包含了一个可变的内部私有的子类引用。如果在反序列一个容器对象的过程中没有特殊的处理来应对子类复制,那么可能在通过向序列化流写入数据过程中夹杂着可能会违反容器类的不可变性的恶意执行。

public void defaultReadObject()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void defaultReadObject() throws IOException, ClassNotFoundException {
SerialCallbackContext ctx = curContext;
if (ctx == null) {
throw new NotActiveException("not in call to readObject");
}
Object curObj = ctx.getObj();
ObjectStreamClass curDesc = ctx.getDesc();
bin.setBlockDataMode(false);
defaultReadFields(curObj, curDesc);
bin.setBlockDataMode(true);
if (!curDesc.hasWriteObjectData()) {
/*
* Fix for 4360508: since stream does not contain terminating
* TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
* knows to simulate end-of-custom-data behavior.
*/
defaultDataEnd = true;
}
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
}

  从流中读取非static、transient关键字修饰的内容。ObjectInputStream自身没有调用该方法,该方法被需要反序列化的类的readObject方法调用。通过defaultReadFields(Object obj, ObjectStreamClass desc)方法完成反序列内容的读取。

private void defaultReadFields(Object obj, ObjectStreamClass desc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private void defaultReadFields(Object obj, ObjectStreamClass desc) 
throws IOException {
Class cl = desc.forClass();
if (cl != null && obj != null && !cl.isInstance(obj)) {
throw new ClassCastException();
}

int primDataSize = desc.getPrimDataSize();
if (primVals == null || primVals.length < primDataSize) {
primVals = new byte[primDataSize];
}
bin.readFully(primVals, 0, primDataSize, false);
if (obj != null) {
desc.setPrimFieldValues(obj, primVals);
}

int objHandle = passHandle;
ObjectStreamField[] fields = desc.getFields(false);
Object[] objVals = new Object[desc.getNumObjFields()];
int numPrimFields = fields.length - objVals.length;
for (int i = 0; i < objVals.length; i++) {
ObjectStreamField f = fields[numPrimFields + i];
objVals[i] = readObject0(f.isUnshared());
if (f.getField() != null) {
handles.markDependency(objHandle, passHandle);
}
}
if (obj != null) {
desc.setObjFieldValues(obj, objVals);
}
passHandle = objHandle;
}

  根据指定类描述符读取被序列化了的字段的内容。第3 ~ 6行代码得到需要反序列的对象的类信息。第8 ~ 15行代码得到对象中基础数据类型字段的数量和字段存储的具体值内容。第18行代码得到对象的所有字段,第19行代码得到对象的非基础数据类型的字段变量内容。第20 ~ 27行代码取得所有非基础数据类型字段存储的值内容。第28 ~ 30行代码完成字段赋值操作。最后更新passHandle。

public ObjectInputStream.GetField readFields()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public ObjectInputStream.GetField readFields()
throws IOException, ClassNotFoundException {
SerialCallbackContext ctx = curContext;
if (ctx == null) {
throw new NotActiveException("not in call to readObject");
}
Object curObj = ctx.getObj();
ObjectStreamClass curDesc = ctx.getDesc();
bin.setBlockDataMode(false);
GetFieldImpl getField = new GetFieldImpl(curDesc);
getField.readFields();
bin.setBlockDataMode(true);
if (!curDesc.hasWriteObjectData()) {
/*
* Fix for 4360508: since stream does not contain terminating
* TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
* knows to simulate end-of-custom-data behavior.
*/
defaultDataEnd = true;
}

return getField;
}

  从流中读取字段变量值(基础数据类型和对象类型),并返回一个GetField实例。

public void registerValidation(ObjectInputValidation obj, int prio)

1
2
3
4
5
6
7
public void registerValidation(ObjectInputValidation obj, int prio)
throws NotActiveException, InvalidObjectException {
if (depth == 0) {
throw new NotActiveException("stream inactive");
}
vlist.register(obj, prio);
}

protected boolean enableResolveObject(boolean enable)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected boolean enableResolveObject(boolean enable)
throws SecurityException {
if (enable == enableResolve) {
return enable;
}
if (enable) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(SUBSTITUTION_PERMISSION);
}
}
enableResolve = enable;
return !enableResolve;
}

public int read()

1
2
3
public int read() throws IOException {
return bin.read();
}

String readTypeString()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
String readTypeString() throws IOException {
int oldHandle = passHandle;
try {
byte tc = bin.peekByte();
switch (tc) {
case TC_NULL:
return (String) readNull();

case TC_REFERENCE:
return (String) readHandle(false);

case TC_STRING:
case TC_LONGSTRING:
return readString(false);

default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
} finally {
passHandle = oldHandle;
}
}

  读取一个字符串且不允许被替换。在ObjectStreamClass.read()方法中被调用。

private boolean isCustomSubclass()

1
2
3
4
private boolean isCustomSubclass() {
// Return true if this class is a custom subclass of ObjectInputStream
return getClass().getClassLoader() != ObjectInputStream.class.getClassLoader();
}

  如果当前类是ObjectInputStream的一个定制子类实现,那么返回true。

private static native void bytesToFloats(byte[] src, int srcpos, float[] dst, int dstpos, int nfloats);

1
2
3
private static native void bytesToFloats(byte[] src, int srcpos,
float[] dst, int dstpos,
int nfloats);

  完成byte向float的转换。native方法,由系统提供并完成处理。

private static native void bytesToDoubles(byte[] src, int srcpos, double[] dst, int dstpos, int ndoubles);

1
2
3
private static native void bytesToDoubles(byte[] src, int srcpos,
double[] dst, int dstpos,
int ndoubles);

  完成byte向double的转换。native方法,由系统提供并完成处理。

涉及基础知识点

  1. Graphs of objects are restored correctly using a reference sharing mechanism.

参考文献

  1. https://blog.csdn.net/kagoy/article/details/12000253
  2. https://blog.csdn.net/abc123lzf/article/details/82318148
  3. https://www.hollischuang.com/archives/1140
  4. https://yq.aliyun.com/articles/646150
  5. http://www.voidcn.com/article/p-xjvhzlxn-nx.html
  6. https://blog.csdn.net/abc123lzf/article/details/82318148
  7. http://www.bubuko.com/infodetail-2129058.html
  8. https://blog.csdn.net/shenchaohao12321/article/details/79521774
  9. https://286.iteye.com/blog/2227942
  10. https://286.iteye.com/blog/2227950
  11. https://xz.aliyun.com/t/2223
  12. http://www.importnew.com/24490.html
  13. http://www.importnew.com/20125.html
  14. http://www.importnew.com/17964.html
  15. http://www.importnew.com/18024.html
  16. https://www.ibm.com/developerworks/cn/java/j-lo-serial/
  17. Java Object Serialization Specification 1.6




------------- End of this article, thanks! -------------


  版权声明:本文由N.C.Lee创作和发表,采用署名(BY)-非商业性使用(NC)-相同方式共享(SA)国际许可协议进行许可,转载请注明作者及出处。
  本文作者为 N.C.Lee
  本文标题为 Java I/O 23 - ObjectInputStream
  本文链接为 https://marcuseddie.github.io/2018/java-ObjectInputStream.html