对比Vector、ArrayList、LinkedList有何区别

这三者都是实现集合框架中的List,也就是所谓的有序集合,因此具体功能也比较近似,比如都提供按照位置进行定位、添加或者删除的操作,都提供迭代器以遍历其内容等。但因 为具体的设计区别,在行为、性能、线程安全等方面,表现又有很大不同。

 

简介

Vector是Java早期提供的线程安全的动态数组,如果不需要线程安全,并不建议选择,毕竟同步是有额外开销的。Vector内部是使用对象数组来保存数据,可以根据需要自动的增加 容量,当数组已满时,会创建新的数组,并拷贝原有数组数据。

    public synchronized void addElement(E obj) {
        modCount++;
        add(obj, elementData, elementCount);
    }

里面基本都是加同步的,可见效率之低。

 

ArrayList是应用更加广泛的动态数组实现,它本身不是线程安全的,所以性能要好很多。与Vector近似,ArrayList也是可以根据需要调整容量,不过两者的调整逻辑有所区 别,Vector在扩容时会提高1倍,而ArrayList则是增加50%。

    private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }

 

LinkedList顾名思义是Java提供的双向链表,所以它不需要像上面两种那样调整容量,它也不是线程安全的。

 

场景

Vector和ArrayList作为动态数组,其内部元素以数组形式顺序存储的,所以非常适合随机访问的场合。除了尾部插入和删除元素,往往性能会相对较差,比如我们在中间位置插 入一个元素,需要移动后续所有元素。

而LinkedList进行节点插入、删除却要高效得多,但是随机访问性能则要比动态数组慢。

总之还是数组和链表的优缺点决定。

 

 

 

 

Java的集合框架,Collection接口是所有集合的根,然后扩展开提供了三大类集合,分别是:

List,也就是我们前面介绍最多的有序集合,它提供了方便的访问、插入、删除等操作。

Set,Set是不允许重复元素的,这是和List最明显的区别,也就是不存在两个对象equals返回true。我们在日常开发中有很多需要保证元素唯一性的场合。

Queue/Deque,则是Java提供的标准队列结构的实现,除了集合的基本功能,它还支持类似先入先出(FIFO, First-in-First-Out)或者后入先出(LIFO,Last-In-FirstOut)等特定行为。这里不包括BlockingQueue,因为通常是并发编程场合,所以被放置在并发包里。

  queue在操作系统上应用场景很多,比如内存分配模型的queue实现。

 

这些集合类,都不是线程安全的,对于java.util.concurrent里面的线程安全容器。但是,并不代表这些集合完全不能支持并发编程的场景, 在Collections工具类中,提供了一系列的synchronized方法,比如:

List list = Collections.synchronizedList(new ArrayList<>());

jdk的实现

        public boolean equals(Object o) {
            if (this == o)
                return true;
            synchronized (mutex) {return list.equals(o);}
        }
        public int hashCode() {
            synchronized (mutex) {return list.hashCode();}
        }

        public E get(int index) {
            synchronized (mutex) {return list.get(index);}
        }
        public E set(int index, E element) {
            synchronized (mutex) {return list.set(index, element);}
        }
        public void add(int index, E element) {
            synchronized (mutex) {list.add(index, element);}
        }
        public E remove(int index) {
            synchronized (mutex) {return list.remove(index);}
        }

它的实现,基本就是将每个基本方法,比如get、set、add之类,都通过synchronizd添加基本的同步支持,非常简单粗暴,但也非常实用。注意这些方法创建的线程安全集合,都 符合迭代时fail-fast行为,当发生意外的并发修改时,尽早抛出ConcurrentModifcationException异常,以避免不可预计的行为。

 

在Java 8之中,Java平台支持了Lambda和Stream,相应的Java集合框架也进行了大范围的增强,以支持类似为集合创建相应stream或者parallelStream的方法实现,我们可以 非常方便的实现函数式代码。

在Java 9中,Java标准类库提供了一系列的静态工厂方法,比如,List.of()、Set.of(),大大简化了构建小的容器实例的代码量。根据业界实践经验,我们发现相当一部分集合实例 都是容量非常有限的,而且在生命周期中并不会进行修改。但是,在原有的Java类库中,我们可能不得不写成:

ArrayLis<String>  lis = new ArrayLis<>();
lis.add("Hello"); 
lis.add("World");

而利用新的容器静态工厂方法,一句代码就够了,并且保证了不可变性。

Lis<String> simpleLis = Lis.of("Hello","world");

 

更进一步,通过各种of静态工厂方法创建的实例,还应用了一些我们所谓的最佳实践,比如,它是不可变的,符合我们对线程安全的需求;它因为不需要考虑扩容,所以空间上更加 紧凑等。

如果我们去看of方法的源码,你还会发现一个特别有意思的地方:我们知道Java已经支持所谓的可变参数(varargs),但是官方类库还是提供了一系列特定参数长度的方法,看起 来似乎非常不优雅,为什么呢?这其实是为了最优的性能,JVM在处理变长参数的时候会有明显的额外开销,如果你需要实现性能敏感的API,也可以进行参考。

jdk的List.of()实现

static final class List12<E> extends AbstractImmutableList<E>
            implements Serializable {

        @Stable
        private final E e0;

        @Stable
        private final E e1;

        List12(E e0) {
            this.e0 = Objects.requireNonNull(e0);
            this.e1 = null;
        }

        List12(E e0, E e1) {
            this.e0 = Objects.requireNonNull(e0);
            this.e1 = Objects.requireNonNull(e1);
        }
...
}

 

可参考

杨晓峰老师的《java核心技术》

https://medium.com/@gilangkusumajati/arraylist-vs-linkedlist-vs-vector-22e1721a66b0

https://www.programcreek.com/2013/03/arraylist-vs-linkedlist-vs-vector/

https://www.cnblogs.com/CherryTab/p/11946157.html

posted @ 2019-12-29 18:46  zhangyu63  阅读(264)  评论(0编辑  收藏  举报