zoukankan      html  css  js  c++  java
  • 对比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

    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    CentOS优化
    C++ 与OpenCV 学习笔记
    常用ubuntu命令
    对极几何笔记
    DBoW2 词袋模型笔记
    OKVIS(一)初始化流程及代码结构
    二进制描述子 BRIEF(ORB), BRISK, FREAK
    VIO 初始化小结
    VINS(十)FeatureManager(未完待续)
    VINS(九)Ceres Solver优化(未完待续)
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12115897.html
Copyright © 2011-2022 走看看