ArrayList可以被持久化吗   虽然他继承了序列化接口,但ArrayList的内容都是存储在
 private transient Object[] elementData;
中的,可是这个数组是个瞬态变量,如果ArrayList能被序列化,可是内容都保存在elementData中,elementDate不能被持久化,那ArrayList又怎么能持久化呢?好像jdk中不只ArrayList是这样,连Map、Set的实现也是这样,用瞬态的变量保存数据,而类本身实现序列化接口,这个我不太明白

解决方案 »

  1.   

    这么理解,ArrayList也是一个实例,这里序列化只是对ArrayList序列化,不过不保存ArrayList持有的实例
      

  2.   

    可是ArrayList的内容都保存在ArrayList持有的实例里了,这个实例没被序列化,那ArrayList就算被序列化,也只是个空壳,还有什么作用呢
      

  3.   

    如果ArrayList持有的对象实现有序列化的话,那么可以序列化成功,如果没有实现,会出现运行时错误。
      

  4.   

    所以说ArrayList是可以被序列化的,但前题是它所持有的对象已经实现了序列化。
      

  5.   

    我猜测是为了其它实现了java.io.Serializable的类方便使用吧。假设有某个类SomeClass实现了Serializable,并且拥有一个类型为ArrayList的成员,这样如果ArrayList没有实现Serializable,那么在序列化类SomeClass的时候就会抛出NotSerializableException。
    这样就必须把每个类型为ArrayList的成员设成transient的,会比较麻烦
      

  6.   

    可能是因为object[]数组大小不确定吧
      

  7.   

    凡是需要被序列化的对象,均需要 直接或间接地 实现java.io.Serializable接口;
    并且,该对象所持有的其他对象也需要 直接或间接地 实现java.io.Serializable接口;
    否则将引起异常或不能正确地反序列化。
      

  8.   

    问题是ArrayList持有的是瞬态变量,不能不持久化,而这个瞬态变量还保持着ArrayList的数据,这个瞬态变量不能被持久化,那序列化ArrayList还有什么意义
      

  9.   

    凡是需要被序列化的对象,均需要 直接或间接地 实现java.io.Serializable接口;
    并且,该对象所持有的其他对象也需要 直接或间接地 实现java.io.Serializable接口;
    那么private transient Object[] elementData;
    是ArrayList持有的对象,那他有被序列化吗?transient难道不是瞬态的吗?
      

  10.   

    虽然这个数组是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]);
        //...
    }
      

  11.   

    是不错,可是这个方法是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()方法,因为他是私有的,别不能调用,可是还是实现持久化了, 不太明白啊
      

  12.   

    回楼上的,看来你得学习一下序列化的机制了,任意一本参考书都行。如果只是声明了Serializable接口,那么将会采用默认机制,也就是s.defaultWriteObject();如果声明了Serializable接口,并且实现了writeObject方法,那么在序列化的时候将会自动调用此方法。之所以被声明为private的,一方面这是java语言本身的规定,另一方面是因为该方法会被自动调用,而且不希望你去手动调用该方法
      

  13.   

    恩 昨天我跟进JDK源码了,确实如此
    现在明白怎么回事了,但是我还有点问题
    他为什么要把它持有的对象设为瞬态的,瞬态只有在持久化时才起作用,我觉得没太大必要这样,可能是有什么性能的考量,但是不知道为什么
      

  14.   

    ArrayList里的readObject/writeObject里只对elementData专门进行了处理,其他的字段都是通过defaultReadObject/defaultWriteObject自动处理的。所以需要对elementData设transient,以避免defaultReadObject/defaultWriteObject再对elementData对写。
      

  15.   

    那么不把elementData设为transient,不重写readObject/writeObject,而让defaultReadObject/defaultWriteObject来对elementData进行处理不也行吗?为什么非要设为transient呢?还是不解啊
      

  16.   

    楼主可真有钻研精神啊
    我把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。
      

  17.   

    elementData分配的数组是有冗余空间的,序列化只需要传输真实的数据。
      

  18.   

    elementData分配的数组是有冗余空间的。序列化只需要传输实际的数据,传输在内存中的存储结构是没必要的。