java面试中经常被问到list常用的类以及内部实现机制,平时开发也经常用到list集合类,因此做一个源码级别的分析和比较之间的差异。

首先看一下List接口的的继承关系:

list接口继承Collection接口,Collection接口继承Iterable接口。

Iterable接口定义的方法:

public interface Iterable<T> {
    /**
     * Returns an iterator over a set of elements of type T.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();
}

Collection接口中定义的方法:

package java.util;
public interface Collection<E> extends Iterable<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Iterator<E> iterator();
    Object[] toArray();
    <T> T[] toArray(T[] a);
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c);
    boolean removeAll(Collection<?> c);
    boolean retainAll(Collection<?> c);
    void clear();
    boolean equals(Object o);
    int hashCode();
}

所以实现list接口的子类必须实现Iterable和Collection接口中的方法。Iterable可以进行元素的迭代。

List特性:

  1. 可以存放同一种类型的元素。
  2. 内部维护元素之间的顺序,是有序集合。
  3. 元素是可以重复的。

在Java中List接口有3个常用的实现类,分别是ArrayList、LinkedList、Vector。

区别如下:

  1. ArrayList内部存储的数据结构是数组存储。数组的特点:元素可以快速访问。每个元素之间是紧邻的不能有间隔,缺点:数组空间不够元素存储需要扩容的时候会开辟一个新的数组把旧的数组元素拷贝过去,比较消性能。从ArrayList中间位置插入和删除元素,都需要循环移动元素的位置,因此数组特性决定了数组的特点:适合随机查找和遍历,不适合经常需要插入和删除操作。
  2. Vector内部实现和ArrayList一样都是数组存储,最大的不同就是它支持线程的同步,所以访问比ArrayList慢,但是数据安全,所以对元素的操作没有并发操作的时候用ArrayList比较快。
  3. LinkedList内部存储用的数据结构是链表。链表的特点:适合动态的插入和删除。访问遍历比较慢。另外不支持get,remove,insertList方法。可以当做堆栈、队列以及双向队列使用。LinkedList是线程不安全的。所以需要同步的时候需要自己手动同步,比较费事,可以使用提供的集合工具类实例化的时候同步:具体使用List<String>
    springokList=Collections.synchronizedCollection(new 需要同步的类)。
总结
1.内部存储结构区别:
 ArrayList、Vector是数组存储。LinkedList是链表存储。
 
        2.线程安全区别:
ArrayList、LinkedList线程不安全。Vector线程安全。
3.使用场景区别:
使用线程同步的时候Vector类首选或者使用Collections工具类初始化时候同步。
需要经常删除、增加使用LinkedList(链表结构)、经常需要查询迭代使用ArrayList(数组结构)

源码分析:

ArrayList类:
 public boolean add(E e) {
//确保数组存储空间是否已经满了,慢了扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
	//计算存储的位置
        elementData[size++] = e;
        return true;
    }
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

Vector中:

private void ensureCapacityHelper(int minCapacity) {  

     int oldCapacity = elementData.length;  

     if (minCapacity > oldCapacity) {  

         Object[] oldData = elementData;  

         int newCapacity = (capacityIncrement > 0) ?  

        (oldCapacity + capacityIncrement) : (oldCapacity * 2);  

         if (newCapacity < minCapacity) {  

        newCapacity = minCapacity;  

         }  

          elementData = Arrays.copyOf(elementData, newCapacity);  

     }  

 }  

ArrayList和Vector主要区别如下:

)同步性:

Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们自己再去考虑和编写线程安全的代码。

备注:对于Vector&ArrayList、Hashtable&HashMap,要记住线程安全的问题,记住Vector与Hashtable是旧的,是java一诞生就提供了的,它们是线程安全的,ArrayList与HashMap是java2时才提供的,它们是线程不安全的。

(2)数据增长:

ArrayList与Vector都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加ArrayList与Vector的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector默认增长为原来两倍,而ArrayList的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的1.5倍)。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。

总结:即Vector增长原来的一倍,ArrayList增加原来的0.5倍。空说无凭源码看看:

ArrayList中增长定义:

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

Vector中增长定义:

 int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);

ArrayList中什么时候触发克隆数组:

  1. 构造参数是Collection集合子类可能触发。
  2. trimToSize的时候触发。
  3. grow的时候触发。
  4. clone的时候触发。
  5. toArray的时候触发。
大致内容就这多实在不明白的可以联系我,如有错误,欢迎指正。












java中List接口的实现类 ArrayList,LinkedList,Vector 的区别 list实现类源码分析的更多相关文章

  1. 网狐6603 cocos2dx 棋牌、捕鱼、休闲类游戏《李逵捕鱼》手机端完整源码分析及分享

    该资源说明: cocos2d 棋牌.捕鱼.休闲类游戏<李逵捕鱼>手机端完整源码,网狐6603配套手机版源码,可以选桌子,适合新手学习参考,小编已亲测试,绝对完整可编译手机端,下载后将文件考 ...

  2. ArrayList,LinkedList,vector的区别

    1,Vector.ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储. 2.List中的元素有序.允许有重复的元素,Set中的元素无序.不允许有重复元素. ...

  3. Java集合源码分析(五)——HashMap

    简介 HashMap 是一个散列表,存储的内容是键值对映射. HashMap 继承于AbstractMap,实现了Map.Cloneable.java.io.Serializable接口. HashM ...

  4. Java中ArrayList源码分析

    一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...

  5. 【JDK】JDK源码分析-ArrayList

    概述 ArrayList 是 List 接口的一个实现类,也是 Java 中最常用的容器实现类之一,可以把它理解为「可变数组」. 我们知道,Java 中的数组初始化时需要指定长度,而且指定后不能改变. ...

  6. 死磕 java集合之HashSet源码分析

    问题 (1)集合(Collection)和集合(Set)有什么区别? (2)HashSet怎么保证添加元素不重复? (3)HashSet是否允许null元素? (4)HashSet是有序的吗? (5) ...

  7. Java源码分析:关于 HashMap 1.8 的重大更新(转载)

    http://blog.csdn.net/carson_ho/article/details/79373134 前言 HashMap 在 Java 和 Android 开发中非常常见 而HashMap ...

  8. spring源码分析系列 (3) spring拓展接口InstantiationAwareBeanPostProcessor

    更多文章点击--spring源码分析系列 主要分析内容: 一.InstantiationAwareBeanPostProcessor简述与demo示例 二.InstantiationAwareBean ...

  9. Java集合源码分析(六)——ConcurrentHashMap

    目录 简介 源码分析 父类 接口 字段 内部类 1.链表节点结构 2.树根结构 3.树节点结构 方法 1.构造方法 2.基本并发方法 3.初始化表数组的操作 4.修改添加元素 5.统计元素数量 6.扩 ...

  10. Vue3中的响应式对象Reactive源码分析

    Vue3中的响应式对象Reactive源码分析 ReactiveEffect.js 中的 trackEffects函数 及 ReactiveEffect类 在Ref随笔中已经介绍,在本文中不做赘述 本 ...

随机推荐

  1. POJ 3276 Face The Right Way

    Description Farmer John has arranged his N (1 ≤ N ≤ 5,000) cows in a row and many of them are facing ...

  2. linux心得

    cd .. 返回上一级文件夹cd /xxx/xxxx/xx 进入文件夹cd Desktop 进入桌面sudo vim /etc/vim/vimrc 进入vim配置器:w xxx 保存为名为xxx的文件 ...

  3. localeCompare() 方法实现中文的拼音排序

    google了很多次才发现在国外网站上有提示如何比较中文,原文地址:http://www.webdeveloper.com/forum/showthread.php?t=9365 前提:使用Unico ...

  4. 4月18开始看《C++Primer Plus》

    好久没有写博客了,之前也说过水平有限,也写不出什么技术博客,只能写些感悟. 过年之后,陆续做了2.3个项目,刚开始可能不太熟悉流程,怎么和页面传数据?最近一个项目1/2天就写完代码了,真的很简单,主要 ...

  5. JVM常见问题(二)

    6. GC收集器有哪些?它们的特点是? 常见的GC收集器如下图所示,连线代表可搭配使用: 1.Serial收集器(串行收集器) 用于新生代的单线程收集器,收集时需要暂停所有工作线程(Stop the ...

  6. 一个蒟蒻对FFT的理解(蒟蒻也能看懂的FFT)

    建议同学们先自学一下"复数(虚数)"的性质.运算等知识,不然看这篇文章有很大概率看不懂. 前言 作为一个典型的蒟蒻,别人的博客都看不懂,只好自己写一篇了. 膜拜机房大佬 HY 一. ...

  7. [转载]致创业者:APP已死 服务永生

    前几日,有位创业者和我讲他在带领团队做一个将爱踢球的人集中在一起的App,我告诉他你的创业方向错了.原因在于你的目的是要为爱踢球的人提供服务,而你现在却在竭尽全力的做App,你应该做的是设计你为爱踢球 ...

  8. Go 语言教程

    Go 语言教程 Go 是一个开源的编程语言,它能让构造简单.可靠且高效的软件变得容易. Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发, ...

  9. PHP Switch 语句

    PHP Switch 语句 switch 语句用于根据多个不同条件执行不同动作. PHP Switch 语句 如果您希望有选择地执行若干代码块之一,请使用 switch 语句. 语法 switch ( ...

  10. Dynamics 365 你所期待的子网格编辑终于来了

    Dynamics 365的online版本已经在11月1号发布了,on-premises版也在没几天后发布,今天略看了一眼 what's new 一眼就看到了 editable grids,这个不用我 ...