zoukankan      html  css  js  c++  java
  • ArrayList序列化

    ArrayList源代码中的

    private transient E[] elementData;  

    声明为transient,为什么还可以序列化成功呢?

    ArrayList重写了

    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException{
        int expectedModCount = modCount;
        // Write out element count, and any hidden stuff
        s.defaultWriteObject();
    
            // Write out array length
            s.writeInt(elementData.length);
    
        // 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();
        }
        }

     在使用ObjectOutputStream序列化对象时会调用这个writeObject方法。

    第二个问题是为什么要声明为transient呢?

    在google了下,发现主流说法如下:

    ArrayList实现了java.io.Serializable接口,所以ArrayList对象可以序列化到持久存储介质中。ArrayList的主要属性定义如下:
    
        * private static final long serialVersionUID = 8683452581122892189L;
        * private transient Object elementData[];
        * private int size;
    
    
    可以看出serialVersionUID和size都将自动序列化到介质中,但elementData数组对象却定义为transient了。
    也就是说 ArrayList中的所有这些元素都不会自动系列化到介质中。为什么要这样实现?因为elementData数组中存储的
    “元素”其实仅是对这些元素的一个引用,并不是真正的对象,序列化一个对象的引用是毫无意义的,因为序列化是为了
    反序列化,当你反序列化时,这些对象的引用已经不可能指向原来的对象了。所以在这儿需要手工的对ArrayList的元素进
    行序列化操作。这就是writeObject()的作用。

     果真如此么??????

    验证下:

    把ArrayList的内容完全copy到一个新类里面,命名为MyArrayList,如下:

    public class MyArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        private static final long serialVersionUID = 8683452581122892189L;
    
        /**
         * The array buffer into which the elements of the ArrayList are stored.
         * The capacity of the ArrayList is the length of this array buffer.
         */
        private E[] elementData;
    
       。。。。。。。。
    
       private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException{
        int expectedModCount = modCount;
        // Write out element count, and any hidden stuff
        s.defaultWriteObject();
    
         if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        }
    
        /**
         * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
         * deserialize it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
        // Read in size, and any hidden stuff
        s.defaultReadObject();
         }
    
    }

     把transient去掉,write/readObject采用默认方式。

    测试下MyArraylist序列化功能:

    MyArrayList al = new MyArrayList<String>();
            al.add("sssssssssssssssss");
            al.add("bbbbbbbbbbbbbbbbbbt");
            al.add("gggggggggggggggggg");
            
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\al.tmp"));
            oos.writeObject(al);
            
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\al.tmp"));
            
            MyArrayList<String> a = (MyArrayList<String>)ois.readObject();
            for(String s: a)
            {
                System.out.println(s);
            }

     输出结果为:

    sssssssssssssssss
    bbbbbbbbbbbbbbbbbbt
    gggggggggggggggggg

    到此证明:引用序列化无效的说法是错误的,这点在ObjectOutputStream中也有说明。

     

    那是为什么呢?

    既然是数组,要序列化到文件中,那就单独测试下数组对象的序列化和反序列化吧

                    String[] stra = new String[4];
            stra[0] = "mmmmmmmmmm";
            stra[2] = "nnnnnnnnnn";
            
            oos = new ObjectOutputStream(new FileOutputStream("D:\sa.tmp"));
            oos.writeObject(stra);
            
            ois = new ObjectInputStream(new FileInputStream("D:\sa.tmp"));
            
            String[] str  = (String[])ois.readObject();
            for(String s: str)
            {
                System.out.println(s);
            }

     输出结果为:

    mmmmmmmmmm
    null
    nnnnnnnnnn
    null

    从输出结果来看,数组序列化时,不管是否有值,都会将整个数组序列化到文件中。

    由此可以看出,比较靠谱的原因是:

    ArrayList是会开辟多余空间来保存数据的,而系列化和反序列化这些没有存放数据的空间是要消耗更多资源的,所以ArrayList的数组就声明为transient,自己实现write/readObject方法,仅仅系列化已经存放的数据。

     

    http://kakaluyi.iteye.com/blog/870137#

  • 相关阅读:
    杨辉三角(hdu2032)——有待完善
    求平均成绩(hdu2023)
    绝对值排序(2020)——笔记待完善
    母牛的故事(hdu2018)——笔记待完善
    29.数据结构---栈,队列,数组,链表,哈希表
    16.PR将视频剪辑成任意形状
    28.集合1------List
    IDEA选中多行代码向左右移动缩进
    27.集合1------Collection
    IDEA显示单个文件结构
  • 原文地址:https://www.cnblogs.com/549294286/p/3338802.html
Copyright © 2011-2022 走看看