如果一個類不僅實現(xiàn)了Serializable接口碧浊,而且定義了 readObject(ObjectInputStream in)和 writeObject(ObjectOutputStream out)方法娱挨,那么將按照如下的方式進行序列化和反序列化:
ObjectOutputStream會調(diào)用這個類的writeObject方法進行序列化樟结,ObjectInputStream會調(diào)用相應(yīng)的readObject方法進行反序列化。
例:ArrayList集合類。其中elementData用transient修飾,不需要進行序列化。ArrayList自身實現(xiàn)了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又是如何知道一個類是否實現(xiàn)了writeObject方法呢?又是如何自動調(diào)用該類的writeObject方法呢娩鹉?
是通過反射機制實現(xiàn)的攻谁。
ObjectOutputStream的writeObject會根據(jù)傳進來的ArrayList對象得到Class,然后再包裝成 ObjectStreamClass底循,在writeSerialData方法里巢株,會調(diào)用ObjectStreamClass的 invokeWriteObject方法。
注意:s.defaultReadObject()函數(shù)在defaultReadObject()函數(shù)前執(zhí)行熙涤。
作用:
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]