JDK序列化原理总结

参考:https://juejin.im/entry/5bf622436fb9a04a0b21cbe7

JDK序列化方式中,使用ObjectInputStream#readObject进行反序列化,使用ObjectInputStream#writeObject进行序列化,反序列化稍微复杂点,朋友们可以结合文字看源码

ObjectInputStream#readObject:

A 判断子类是否重写了readObject方法。因为readObject是final修饰,所以实质上重写的是readObjectOveride方法,如果重写了,则直接执行子类重写的readObjectOverride方法。

B 如果没有,则指向readObject0,readObject0就是底层执行反序列化的主要方法:

1 选择反序列化方法

2 如果是反序列化对象,则会执行readOrdinaryObject方法:

1 反序列化创建了新的对象,这就是反序列化可以破坏单例的原因;

2 判断序列化方式,可以看到实现Externalizable接口的方式优先级要高于实现Serializable接口的方式,如果使		用的是Serializable方式,则会执行readSerialData方法:

		1 判断被序列化的类中是否包含readObject方法;(hasReadObjectMethod)

		2 如果包含,就执行被序列化类中的readObject方法;(HashMap、ArrayList重写了)

		3 如果不包含, 执行ObjectInputStream默认的defaultReadFields方法。

3 判断被序列化的类是否包含readResolve方法,如果包含,则执行readResolve方法,并使用该方法返回的对		象替换之前创建的obj(代码obj=rep进行的替换,解决单例序列化的问题)。

ObjectInputStream#writeObject原理类似,对反序列化的数据按照顺序读取而已:

A 判断子类是否重写了writeObject方法。因为writeObject是final修饰,所以实质上重写的是writeObjectOveride方法,如果重写了,则直接执行子类重写的writeObjectOverride方法。

B 如果没有,则指向writeObject0,writeObject0就是底层执行序列化的主要方法:

1 选择序列化方法

2 如果是序列化对象,则会执行writeOrdinaryObject方法:

1 判断序列化方式,可以看到实现Externalizable接口的方式优先级要高于实现Serializable接口的方式,如果使		用的是Serializable方式,则会执行writeSerialData方法:

		1 判断被序列化的类中是否包含writeObject方法;(hasWriteObjectMethod)

		2 如果包含,就执行被序列化类中的writeObject方法;(HashMap、ArrayList重写了)

		3 如果不包含, 执行ObjectOutStream默认的defaultWriteFields方法。

HashMap如果不重写writeObject和readObject:假设机器A要传输一个HashMap到机器B,且AB对于hashCode()的实现不一致,那么在A将HashMap整个序列化到B后,Entry上元素的位置在两个机器是一样的,但是因为hashCode()不一样,如果此时B要获取key=”pdc“这个元素,这个元素在A上存储的时候,位置为0,而到了B,通过hashCode()和HashMap的get方法得到的位置却为1,那么得到的就不是key=”pdc“了,而是其他key。

所以为了一致性,直接重写writeObject和readObject,A直接传输key和value,让B自己根据自己的hashCode()重新put进Entry,如key=”pdc“,put的位置为1,这样AB两台机器上的HashMap虽然Entry上元素的位置不一样,但是两台机器并不互相影响,而此时B通过hashCode()和HashMap的get方法得到key=”pdc“的位置为1,这样就一致了

ArrayList则是因为在ArrayList中的数组容量基本上都会比实际的元素的数大, 为了避免序列化没有元素的数组而重写.

你可能感兴趣的:(Java基础)