1: 先閱讀這邊文章:http://www.importnew.com/21517.html
2:被transient修飾真的會被序列化嗎?
反例:java.util.ArrayList中底層存儲數組就是transient,但是實際上還是可以被成功序列化。具體原因如下:
transient Object[] elementData;
我的測試代碼:
class ArrayListDemo implements Serializable {
public static void main(String[] args) throws Exception {
ArrayList<Integer> data = new ArrayList<>();
data.add(1);
data.add(1);
data.add(1);
data.add(1);
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bo);
out.writeObject(data);
byte[] dataData = bo.toByteArray();
FileOutputStream fo = new FileOutputStream("data.dat");
fo.write(dataData);
fo.close();
FileInputStream fi = new FileInputStream("data.dat");
ObjectInputStream in = new ObjectInputStream(fi);
ArrayList<Integer> newList = (ArrayList<Integer>) in.readObject();
System.out.println(newList.size());
for (int i = 0; i < newList.size(); i++) {
System.out.println(newList.get(i));
}
}
}
輸出:

數據還是成功序列化了,為什么會被序列化呢?分析原因還是需要看源碼,就以java.io.ObjectOutputStream#writeObject寫對象為入手點,跟蹤源碼會跟中到如下方法java.io.ObjectStreamClass#invokeWriteObject:

方法源碼如下:
void invokeWriteObject(Object obj, ObjectOutputStream out)
throws IOException, UnsupportedOperationException
{
requireInitialized();
if (writeObjectMethod != null) {
try {
writeObjectMethod.invoke(obj, new Object[]{ out });
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof IOException) {
throw (IOException) th;
} else {
throwMiscException(th);
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
}
}
通過debug可以看到最終調用的是java.util.ArrayList#writeObject ,java.util.ArrayList#writeObject源碼如下:
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();
}
}ke
可以看出最終將elementData寫出去了。反序列化同理不在分析。
重點來了,name為什么JDK需要這么做呢?原因如下:
JDK為什么不直接用elementData來序列化,而采用上訴的方式來實現序列化呢?原因在於elementData是一個緩存數組,它通常會預留一些容量,等容量不足時再擴充容量,那么有些空間可能就沒有實際存儲元素,采用上訴的方式來實現序列化時,就可以保證只序列化實際存儲的那些元素,而不是整個數組,從而節省空間和時間。
小提示:
java.io.ObjectOutputStream#writeObject中的enableOverride字段可以自行實現writeObjectOverride方法,對於enableOverride=true需要通過實現ObjectOutputStream的子類實現自定義寫對象。
