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的子类实现自定义写对象。