Java中,序列化及反序列化的底层原理

序列化及反序列化的底层原理今天我们深入分析一下JAVA序列化及反序列化的原理 。
为了方便读者理解,下面通过ArrayList的序列化来展开介绍Java是如何实现序列化及反序列化的 。
在介绍ArrayList序列化之前,先考虑一个问题:
如何自定义序列化和反序列化的策略?带着这个问题,我们看一下java.util.ArrayList的源码:
public class ArrayList<E> extends AbstractList<E>implements List<E>, Randomaccess, Cloneable, java.io.Serializable{private static final long serialVersionUID = 8683452581122892189L;transient Object[] elementData; // non-private to simplify nested class accessprivate int size;}上面的代码中忽略了其他成员变量,ArrayList实现了java.io.Serializable接口,我们对它进行序列化及反序列化 。
我们看到,ArrayList中的elementData被定义为transient类型,而被定义为transient类型的成员变量不会被序列化而保留下来 。
我们写一个Demo,验证一下我们的想法:
public static void main(String[] args) throws IOException, ClassNotFoundException {List<String> stringList = new ArrayList<String>();stringList.add("hello");stringList.add("world");stringList.add("hollis");stringList.add("chuang");System.out.println("init StringList" + stringList);ObjectOutputStream objectOutputStream = new ObjectOutputStream(newFileOutputStream("stringlist"));objectOutputStream.writeObject(stringList);IOUtils.close(objectOutputStream);File file = new File("stringlist");ObjectInputStream objectInputStream = new ObjectInputStream(newFileInputStream(file));List<String> newStringList = (List<String>)objectInputStream.readObject();IOUtils.close(objectInputStream);if(file.exists()){file.delete();}System.out.println("new StringList" + newStringList);}// init StringList[hello, world, hollis, chuang]// new StringList[hello, world, hollis, chuang]了解ArrayList的读者都知道,ArrayList底层是通过数组实现的 。那么数组elementData其实就是用来保存列表中的元素的 。通过该属性的声明方式我们知道,它是无法通过序列化持久化下来的 。
那么为什么上面代码的结果却通过序列化和反序列化把List中的元素保留下来了呢?
1. writeObject 和readObject 方法在ArrayList中定义了两个方法:writeObject和readObject 。
这里先给出结论:在序列化过程中,如果被序列化的类中定义了writeObject和readObject方法,那么虚拟机会试图调用对象类中的writeObject和readObject方法进行用户自定义的序列化和反序列化操作 。
如果没有这样的方法,则默认调用的是ObjectOutputStream的defaultWriteObject方法和ObjectInputStream的defaultReadObject方法 。
用户自定义的writeObject和readObject方法允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值 。
下面看一下这两个方法的具体实现:
private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {elementData = https://www.isolves.com/it/cxkf/yy/JAVA/2022-08-10/EMPTY_ELEMENTDATA;// Read in size, and any hidden stuffs.defaultReadObject();// Read in capacitys.readInt(); // ignoredif (size > 0) {// be like clone(), allocate array based upon size not capacityensureCapacityInternal(size);Object[] a = elementData;// Read in all elements in the proper order.for (int i=0; i


推荐阅读