ArrayList可以被持久化吗

zfq642773391 2010-04-16 03:27:36
ArrayList可以被持久化吗 虽然他继承了序列化接口,但ArrayList的内容都是存储在
private transient Object[] elementData;
中的,可是这个数组是个瞬态变量,如果ArrayList能被序列化,可是内容都保存在elementData中,elementDate不能被持久化,那ArrayList又怎么能持久化呢?好像jdk中不只ArrayList是这样,连Map、Set的实现也是这样,用瞬态的变量保存数据,而类本身实现序列化接口,这个我不太明白
...全文
591 28 打赏 收藏 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
无所不能老徐 2010-05-08
  • 打赏
  • 举报
回复
看看。帮顶
wangfanee 2010-04-18
  • 打赏
  • 举报
回复
讨论的很激烈啊,对序列化认识更深了。。。
zhangaiqiang888 2010-04-18
  • 打赏
  • 举报
回复
学习学习
zfq642773391 2010-04-18
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 taolei 的回复:]
ArrayList里的readObject/writeObject里只对elementData专门进行了处理,其他的字段都是通过defaultReadObject/defaultWriteObject自动处理的。所以需要对elementData设transient,以避免defaultReadObject/defaultWriteObject再对elementData对写。
[/Quote]
那么不把elementData设为transient,不重写readObject/writeObject,而让defaultReadObject/defaultWriteObject来对elementData进行处理不也行吗?为什么非要设为transient呢?还是不解啊
niulei190922 2010-04-18
  • 打赏
  • 举报
回复
学习一下...
taolei 2010-04-18
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 zfq642773391 的回复:]
那么不把elementData设为transient,不重写readObject/writeObject,而让defaultReadObject/defaultWriteObject来对elementData进行处理不也行吗?为什么非要设为transient呢?还是不解啊[/Quote]
elementData分配的数组是有冗余空间的。序列化只需要传输实际的数据,传输在内存中的存储结构是没必要的。
taolei 2010-04-18
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 zfq642773391 的回复:]
引用 17 楼 taolei 的回复:
ArrayList里的readObject/writeObject里只对elementData专门进行了处理,其他的字段都是通过defaultReadObject/defaultWriteObject自动处理的。所以需要对elementData设transient,以避免defaultReadObject/defaultWriteObject再对eleme……
[/Quote]
elementData分配的数组是有冗余空间的,序列化只需要传输真实的数据。
groovy2007 2010-04-18
  • 打赏
  • 举报
回复
楼主可真有钻研精神啊
我把jdk相关代码又看了一遍,觉得ArrayList类实现writeObject方法的原因并发有关
完整代码是这样的:

private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{
int expectedModCount = modCount;
s.defaultWriteObject();
s.writeInt(elementData.length);
for (int i=0; i<size; i++)
s.writeObject(elementData[i]);

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


modCount是从AbstractList继承来的一个protected字段,主要用来在并发环境下检查List有没有被修改。
如果在序列化的过程中列表被另一个线程修改了,那么就抛出异常。

如果只是声明了Serializable,但是不实现writeObject,就不会有这种检查。

当然,手工实现writeObject方法,仍然可以不将elementData设为瞬时的,而是通过s.defaultWriteObject()将数组写入。但是我猜想,既然反正要手工实现writeObject,不如手动将所有元素依次写入,这样可以少一层函数调用(数组的defaultWriteObject显然也是那样一个循环),提高效率;另一方面,也是为了遵循“依据逻辑而不是底层实现”的原则,提高了灵活性,见Effective Java条款之Consider using a custom serialized form。
hjjk123 2010-04-18
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 libitum_1 的回复:]

[/Quote]

刚试了下! 9#说的对!有学习了!
hjjk123 2010-04-18
  • 打赏
  • 举报
回复
XueXi....................
chensjmail 2010-04-18
  • 打赏
  • 举报
回复
可以的,你自己試一下寫一個例子,我記得以前用過的.
zfq642773391 2010-04-17
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 groovy2007 的回复:]
回楼上的,看来你得学习一下序列化的机制了,任意一本参考书都行。

如果只是声明了Serializable接口,那么将会采用默认机制,也就是s.defaultWriteObject();

如果声明了Serializable接口,并且实现了writeObject方法,那么在序列化的时候将会自动调用此方法。之所以被声明为private的,一方面这是java语言本身的规定,另一方面是因为该方法会……
[/Quote]
恩 昨天我跟进JDK源码了,确实如此
现在明白怎么回事了,但是我还有点问题
他为什么要把它持有的对象设为瞬态的,瞬态只有在持久化时才起作用,我觉得没太大必要这样,可能是有什么性能的考量,但是不知道为什么
groovy2007 2010-04-17
  • 打赏
  • 举报
回复
回楼上的,看来你得学习一下序列化的机制了,任意一本参考书都行。

如果只是声明了Serializable接口,那么将会采用默认机制,也就是s.defaultWriteObject();

如果声明了Serializable接口,并且实现了writeObject方法,那么在序列化的时候将会自动调用此方法。之所以被声明为private的,一方面这是java语言本身的规定,另一方面是因为该方法会被自动调用,而且不希望你去手动调用该方法
taolei 2010-04-17
  • 打赏
  • 举报
回复
ArrayList里的readObject/writeObject里只对elementData专门进行了处理,其他的字段都是通过defaultReadObject/defaultWriteObject自动处理的。所以需要对elementData设transient,以避免defaultReadObject/defaultWriteObject再对elementData对写。
zfq642773391 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 groovy2007 的回复:]
虽然这个数组是transient的:private transient Object[] elementData

但是ArrayList实现了writeObject方法,在该方法里会将数组元素依次写入。
在序列化的时候会调用writeObject方法。

Java code

private void writeObject(java.io.ObjectOutputStream ……
[/Quote]
是不错,可是这个方法是private的,除了ArrayList,别的对象都不能调用它,可是看下面

File myObjectFile=new File("d:\\1.txt");
ObjectOutputStream oos;
oos=new ObjectOutputStream(new FileOutputStream(myObjectFile));
ArrayList<Integer> a=new ArrayList<Integer>();
a.add(1);
a.add(2);
oos.writeObject(a);
oos.close();

虽然成功的把ArrayList持久化了,可是并没有调用ArrayList的writeObject()方法,因为他是私有的,别不能调用,可是还是实现持久化了, 不太明白啊
groovy2007 2010-04-16
  • 打赏
  • 举报
回复
虽然这个数组是transient的:private transient Object[] elementData

但是ArrayList实现了writeObject方法,在该方法里会将数组元素依次写入。
在序列化的时候会调用writeObject方法。

private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{
//...
s.defaultWriteObject();
s.writeInt(elementData.length);
for (int i=0; i<size; i++)
s.writeObject(elementData[i]);
//...
}
zfq642773391 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 yaray 的回复:]
那你的这个序列化的命题本身就是错误的。

上面的回复只是说明一下可正确序列化的条件,无他。
[/Quote]
凡是需要被序列化的对象,均需要 直接或间接地 实现java.io.Serializable接口;
并且,该对象所持有的其他对象也需要 直接或间接地 实现java.io.Serializable接口;
那么private transient Object[] elementData;
是ArrayList持有的对象,那他有被序列化吗?transient难道不是瞬态的吗?
yaray 2010-04-16
  • 打赏
  • 举报
回复
那你的这个序列化的命题本身就是错误的。

上面的回复只是说明一下可正确序列化的条件,无他。
zfq642773391 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 yaray 的回复:]
凡是需要被序列化的对象,均需要 直接或间接地 实现java.io.Serializable接口;
并且,该对象所持有的其他对象也需要 直接或间接地 实现java.io.Serializable接口;
否则将引起异常或不能正确地反序列化。
[/Quote]
问题是ArrayList持有的是瞬态变量,不能不持久化,而这个瞬态变量还保持着ArrayList的数据,这个瞬态变量不能被持久化,那序列化ArrayList还有什么意义
libitum_1 2010-04-16
  • 打赏
  • 举报
回复
加载更多回复(8)

62,620

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧