• 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#

  • 相关阅读:
    MongoDB Query 的几个方法
    jQuery日期和时间插件(jqueryuitimepickeraddon.js)中文破解版使用
    entity framework使用技巧
    SQL Server TSQL高级查询
    Visual Studio 2012资源管理器里单击打开改为双击打开文件
    ASP.NET MVC 3发布报错(ASP.NET MVC 3在没有安装环境的服务器上运行)的解决方案
    排序算法时间测试比较
    读书笔记之:C++ STL 开发技术导引3
    如何判断整数x的二进制中含有多少个1
    面试题:2012民生银行总行笔试题
  • 原文地址:https://www.cnblogs.com/549294286/p/3338802.html
Copyright © 2020-2023  润新知