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. 【Uva 10269 马里奥与公主的归途】

    ·马里奥n次解救了公主,现在需要从魔王的宫殿返回. ·英文题,述大意:      给定一个点数不超过100的无向图,其中的点分为两类:乡村和城堡. 输入A个乡村,B个城堡(乡村编号1~A,城堡编号A+ ...

  2. python 程序中调用go

    虽然python优点很多,但是有一个致命的缺点就是运行速度太慢,那么python程序需要一些计算量比较大的模块时一般会调用c或者c++的代码来重写,但是c/c++编写代码代价太高,耗费太多的人力.那么 ...

  3. 基于pytorch实现HighWay Networks之Highway Networks详解

    (一)简述---承接上文---基于pytorch实现HighWay Networks之Train Deep Networks 上文已经介绍过Highway Netwotrks提出的目的就是解决深层神经 ...

  4. js去除空格,判断是否包含

    js去除空格 function trimStr(str){ return str.replace(/(^\s*)|(\s*$)/g,""); } js判断是否包含 //是否包含 f ...

  5. Vue.js + Webpack

    vue.js Vue.js是一个构建数据驱动的 web 界面的库.Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件 以上是Vue.js官方定义,故名思议,以数据驱动视 ...

  6. Tomcat出现validateJarFile-jar not loaded问题

    tomcat启动时问题: validateJarFile(...\WEB-INF\lib\servlet-api.jar)-jar not loaded. See Servlet Spec 2.3, ...

  7. angular+ionic前后端分离开发项目中的使用

    Ionic基于AngularJS构建而成,所以学习一些AngularJS的知识很有必要.Ionic并没有独立开发一套完整的Web应用框架,而是对AngularJS进行了扩展,给它添加了大量界面组件和其 ...

  8. mongodb数据库备份迁移 windows -> linux

    mongodb数据库备份迁移 windows -> linux cd 到本机mongodb的安装目录 如: C:\Program Files\MongoDB\Server\3.4\bin 可以发 ...

  9. 使用RedisDesktopManager工具,解决连接失败问题

    今天在云服务器上搭建好了redis环境,想用RedisDesktopManager工具去连接一下,结果连接不上,显示如下图: 我确保了服务器防火墙关闭,又在redis配置文件中设置了requirepa ...

  10. 转:linux/unix命令行终端的光标及字符控制快捷键

    from:http://linux.chinaunix.net/techdoc/system/2007/11/23/973027.shtml 在使用linux/unix的命令行终端时,有时候会碰到键盘 ...