Home > Archives > Java学习-Vector vs ArrayList

Java学习-Vector vs ArrayList

Publish:

在写jdk util库的时候,经常会被一些细节问题搞的莫名其妙。
比如之前的静态私有内部类的问题。
这次又注意到Vector与ArrayList的实现定义的存储结构上。

要深入理解,需要从各种角度来考虑设计的思路,但由于经验匮乏,很多时候还是想不到。

问题

先看两个定义:

1
ArrayList: private transient Object[] elementData;

1
Vector: protected Object[] elementData;

ArrayList使用了transient关键字进行存储优化,而Vector没有这样做,为什么?

transient

Java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。这里的对象存储是指,Java的serialization提供的一种持久化对象实例的机制。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。使用情况是:当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。

ArrayList

    /**
     * Save the state of the <tt>ArrayList</tt> instance to a stream (that
     * is, serialize it).
     *
     * @serialData The length of the array backing the <tt>ArrayList</tt>
     *             instance is emitted (int), followed by all of its elements
     *             (each an <tt>Object</tt>) in the proper order.
     */
    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 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();
        }

    }

ArrayList实现了writeObject方法,可以看到只保存了非null的数组位置上的数据。即list的size个数的elementData。需要额外注意的一点是,ArrayList的实现,提供了fast-fail机制,可以提供弱一致性。

Vector

    /**
     * Save the state of the {@code Vector} instance to a stream (that
     * is, serialize it).
     * This method performs synchronization to ensure the consistency
     * of the serialized data.
     */
    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException {
        final java.io.ObjectOutputStream.PutField fields = s.putFields();
        final Object[] data;
        synchronized (this) {
            fields.put("capacityIncrement", capacityIncrement);
            fields.put("elementCount", elementCount);
            data = elementData.clone();
        }
        fields.put("elementData", data);
        s.writeFields();
    }

Vector也实现了writeObject方法,但方法并没有像ArrayList一样进行优化存储,实现语句是

1
data = elementData.clone();

clone()的时候会把null值也拷贝。所以保存相同内容的Vector与ArrayList,Vector的占用的字节比ArrayList要多。

可以测试一下,序列化存储相同内容的Vector与ArrayList,分别到一个文本文件中去。

分析:

ArrayList是非同步实现的一个单线程下较为高效的数据结构(相比Vector来说)。
ArrayList只通过一个修改记录字段提供弱一致性,主要用在迭代器里。没有同步方法。 即上面提到的Fast-fail机制.ArrayList的存储结构定义为transient,重写writeObject来实现自定义的序列化,优化了存储。

Vector是多线程环境下更为可靠的数据结构,所有方法都实现了同步。
而关于为什么Vector没有在序列化的时候跟ArrayList一样去优化存储,这个问题没考虑清楚。

区别

1
ArrayList: int newCapacity = oldCapacity + (oldCapacity >> 1);

ArrayList自动扩大容量为原来的1.5倍(实现的时候,方法会传入一个期望的最小容量,若扩容后容量仍然小于最小容量,那么容量就为传入的最小容量。扩容的时候使用的Arrays.copyOf方法最终调用native方法进行新数组创建和数据拷贝)

1
Vector: int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);

Vector指定了initialCapacity,capacityIncrement来初始化的时候,每次增长capacityIncrement

建议

参考

  1. ArrayList,Vector区别

http://xinklabi.iteye.com/blog/1882251 http://blog.csdn.net/skill1986/article/details/6771528

  1. failfast机制

http://blog.csdn.net/lianyu2008/article/details/4651451

  1. java util包分析(里面Vector分析有点瑕疵,针对范型编程的时候不是存储什么类型都可以,有空再分析)

http://blog.tianya.cn/blogger/post_show.asp?BlogID=229728&PostID=10038711

  1. Vector ArrayList的序列化方面的区别

http://www.oschina.net/question/587433_76759?sort=time http://www.coderanch.com/t/585905/java/java/Difference-serialization-Vector-ArrayList http://stackoverflow.com/questions/9848129/why-does-arraylist-use-transient-storage/9848179#9848179

声明: 本文采用 BY-NC-SA 授权。转载请注明转自: tsui

Comments
comments powered by Disqus(如果评论显示不出来,则需要fan墙)