Java-序列化 —(二)

如果一个类不仅实现了Serializable接口,而且定义了 readObject(ObjectInputStream in)和 writeObject(ObjectOutputStream out)方法,那么将按照如下的方式进行序列化和反序列化:

ObjectOutputStream会调用这个类的writeObject方法进行序列化,ObjectInputStream会调用相应的readObject方法进行反序列化。

例:ArrayList集合类。其中elementData用transient修饰,不需要进行序列化。ArrayList自身实现了writeObject和readObject方法。

ArrayList源码

    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

   private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }

那么ObjectOutputStream又是如何知道一个类是否实现了writeObject方法呢?又是如何自动调用该类的writeObject方法呢?
是通过反射机制实现的。

ObjectOutputStream的writeObject会根据传进来的ArrayList对象得到Class,然后再包装成 ObjectStreamClass,在writeSerialData方法里,会调用ObjectStreamClass的 invokeWriteObject方法。

注意:s.defaultReadObject()函数在defaultReadObject()函数前执行。
作用:
1、It reads and writes all the non transient fields of the class respectively.

2、 These methods also helps in backward and future compatibility. If in future you add some non-transient field to the class and you are trying to deserialize it by the older version of class then the defaultReadObject() method will neglect the newly added field, similarly if you deserialize the old serialized object by the new version then the new non transient field will take default value from JVM

/**
 * FileName: ArrayListTest
 * Author:   Sandy
 * Date:     2018/12/1 14:25
 * Description:
 * Version: v1.0.0
 */

package AggregationDemo;

import java.io.*;
import java.util.ArrayList;

public class ArrayListTest {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

            ArrayList arrayList = new ArrayList();

            arrayList.add(1);
            arrayList.add("123");


            System.out.println("1. 原始对象:" + arrayList);

            //ArrayList序列化
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("ArrayListTest"));
            outputStream.writeObject(arrayList);

            //反序列化
            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("ArrayListTest"));
            ArrayList arrayList_other = (ArrayList) inputStream.readObject();

            arrayList.add(123.312);
            arrayList_other.add("abc");

            System.out.println("2. 原始对象:" + arrayList);
            System.out.println("3. 拷贝对象:" + arrayList_other);
    }

}

输出

1. 原始对象:[1, 123]
2. 原始对象:[1, 123, 123.312]
3. 拷贝对象:[1, 123, abc]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。