Java集合List实现原理

一、集合类结构

Java中的集合包含多种数据结构,如链表、队列、哈希表等。从类的继承结构来说,可以分为两大类,一类是继承自Collection接口,这类集合包含List、Set和Queue等集合类。另一类是继承自Map接口,这主要包含了哈希表相关的集合类。

1.继承Collection接口

2.继承Map接口

二、实现原理

1.List (有序,可重复)

常用的实现List接口的主要有ArrayList、Vector、LinkedList 三个,通过查看jdk底层源码实现,进行简单的要点总结:

(1)ArrayList

ArrayList是List使用中最常用的实现类,它的查询速度快,效率高,但增删慢,线程不安全。

实现原理:

ArrayList底层实现采用的数据结构是数组,并且数组默认大小为10,所以下面两种方式是等同的:

List list = new ArrayList();  //没有指定数组大小,使用默认值(默认大小是10)

List list = new ArrayList(10);  // 指定数组大小为10,传如的参数便是数组的大小,传入为10时,跟默认值相同,所以是等同的

要想清楚的理解上面两中方式,从ArrayList类的构造器就会豁然开朗:

注:不同的jdk版本实现代码有所不同, 现以jdk1.8为例(个人感觉  jdk1.6的底层实现写法更好理解,jdk1.8就比1.6较难懂一些)

// 无参构造器public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;   // DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个默认大小的空实例
}

// 有参构造器,参数为列表的初始容量(由于是通过数组实现的,所以可以理解成数组的大小)
public ArrayList(int initialCapacity) {
  if (initialCapacity > 0) {
    this.elementData = new Object[initialCapacity];
  } else if (initialCapacity == 0) {
    this.elementData = EMPTY_ELEMENTDATA;
  } else {
    throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
  }
}

扩容机制:

jdk1.8的扩容算法:newCapacity = oldCapacity + ( oldCapacity >> 1 ) ;   // oldCapacity >> 2  移位运算,此处相当于oldCapacity除以2,但是 >> 这种写法更加高效

jdk1.6的扩容算法:newCapacity = ( oldCapacity * 3 ) / 2 +1 ;

参数介绍:newCapacity 是扩容后的容量大小,oldCapacity 是扩容前的大小

查看jdk源码,移位运算需要学习下,换句话说,就是需要学习下二进制,比如:反码、补码,二进制与十进制、十六进制的相互转换。与机器交流的都是0110等,所以挺重要的。

(2)Vector

Vector的底层也是通过数组实现的,默认大小也是10。主要特点:查询快,增删慢  , 线程安全,但是效率低

实现原理:

创建对象与ArrayList类似,但有一点不同,它可以设置扩容是容量增长大小。

根据Vector的三个构造器就可以很明了的理解 new Vector(); 与 new Vector(10);与 new Vector(10,0); 三个是等同的,很明了就不赘述了。

1.无参构造器 public Vector() {
        this(10);
    }

2.传一个参数(容量大小) 容量大小即底层数组大小
public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
3.传两个参数(容量大小,容量修正) 容量修正即扩容时的增加量
public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

扩容机制:

jdk1.8的扩容算法:newCapacity = oldCapacity + ( ( capacityIncrement > 0 ) ? capacityIncrement : oldCapacity );

jdk1.6的扩容算法:newCapacity = ( capacityIncrement > 0 ) ? ( oldCapacity + capacityIncrement ) : (  oldCapacity  * 2 );

参数介绍:capacityIncrement 是容量修正(即容量新增大小),没有设置,默认为0    ,newCapacity 是扩容后的容量大小,oldCapacity 是扩容前的大小

一观察,就会发现1.6与1.8的写法变化不大,但是仔细一分析,就会发现jdk1.6中有使用乘法运算,即 oldCapacity  * 2。 在jdk1.8中换成了加法运算,这是因为乘法的效率是低于加法的,这应该算法的优化。

(3)LinkedList

LinkedList底层是一个双向链表,它增删快,效率高,但是查询慢,线程不安全

实现原理:

构造器只有如下两种;

1.无参构造
public LinkedList() {
    }

2.有参构造
public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

由于它的底层实现是链表,所以没有容量大小的定义,只有上个节点,当前节点,下个节点,每个节点都有一个上级节点和一个下级节点。

新增元素:

1.头部新增

实现代码如下:

private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
        modCount++;
    }

先获取头部节点元素,判断是否为null,若为null,说明原链表中没有元素,则把 first 和 last 都赋为当前新增节点。

                  若不为null,说明原链表中有元素,则把first赋为当前新增节点,把原头部节点f的上级节点修改为当前新增节点的下级节点

2.尾部新增

void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

与头部新增元素类似,不再赘述。

删除元素:

删除元素有三种方式,删除第一元素,删除最后一个元素,删除中间部分的某个元素。   现介绍最后一个,最后一个搞懂了,前两个就懂了。

实现代码:

E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        modCount++;
        return element;
    }

原理:要删除元素的当前节点x,将当前节点x的上级节点的下级节点设为当前节点x的下级节点,将当前节点x的下级节点的上级节点设为当前节点x的上级节点。

     中间考虑上级节点或下级节点为空的情况,也就是头部删除与尾部删除。

原文地址:https://www.cnblogs.com/kanglijun/p/10999247.html

时间: 2024-08-30 14:29:53

Java集合List实现原理的相关文章

1.Java集合-HashMap实现原理及源码分析

哈希表(Hash  Table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出现在各类的面试题中,这里对java集合框架中的对应实现HashMap的实现原理进行讲解,然后对JDK7的HashMap的源码进行分析 哈希算法,是一类算法: 哈希表(Hash  Table)是一种数据结构: 哈希函数:是支撑哈希表的一类函数: HashMap 是 Java中用哈希数据结构实现的Ma

Java集合:ConcurrentHashMap原理分析

集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主要分析jdk1.5的3种并发集合类型(concurrent,copyonright,queue)中的ConcurrentHashMap,让我们从原理上细致的了解它们,能够让我们在深度项目开发中获益非浅. 通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张

Java集合~ConcurrentHashMap原理

集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).文章主要分析jdk1.5的3种并发集合类型(concurrent,copyonright,queue)中的ConcurrentHashMap,让我们从原理上细致的了解它们,能够让我们在深度项目开发中获益非浅. 通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张表让

6.Java集合-LinkedList实现原理及源码分析

Java中LinkedList的部分源码(本文针对1.7的源码) LinkedList的基本结构 jdk1.7之后,node节点取代了 entry ,带来的变化是,将1.6中的环形结构优化为了直线型链表结构,从双向循环链表变成了双向链表 在LinkedList中,我们把链子的"环"叫做"节点",每个节点都是同样的结构.节点与节点之间相连,构成了我们LinkedList的基本数据结构,也是LinkedList的核心. 我们再来看一下LinkedList在jdk1.6和

Java集合 LinkedList的原理及使用

LinkedList和ArrayList一样是集合List的实现类,虽然较之ArrayList,其使用场景并不多,但同样有用到的时候,那么接下来,我们来认识一下它. 一. 定义一个LinkedList public static void main(String[] args) { List<String> stringList = new LinkedList<>(); List<String> tempList = new ArrayList<>();

2.Java集合-ConcurrentHashMap实现原理及源码分析

一.为何用ConcurrentHashMap 在并发编程中使用HashMap可能会导致死循环,而使用线程安全的HashTable效率又低下. 线程不安全的HashMap 在多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap 效率低下的HashTable Hashtable使用synchronized来保证线程的安全,但是在线程竞争激烈的情况下Hashtable的效率非常低下.当一个线程访问Hashtable的同步方法,

【转】Java 集合系列04之 fail-fast总结(通过ArrayList来说明fail-fast的原理、解决办法)

概要 前面,我们已经学习了ArrayList.接下来,我们以ArrayList为例,对Iterator的fail-fast机制进行了解.内容包括::1 fail-fast简介2 fail-fast示例3 fail-fast解决办法4 fail-fast原理5 解决fail-fast的原理 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3308762.html 1 fail-fast简介 fail-fast 机制是java集合(Collection)中

深入Java集合学习系列:HashMap的实现原理

参考文献 引用文献:深入Java集合学习系列:HashMap的实现原理,大部分参考这篇博客,只对其中进行稍微修改 自己曾经写过的:Hashmap实现原理 1. HashMap概述: HashMap是基于哈希表的Map接口的非同步实现(Hashtable跟HashMap很像,唯一的区别是Hashtalbe中的方法是线程安全的,也就是同步的).此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序恒久不变. 2. HashMap的数据结构: 在ja

Java 集合系列04之 fail-fast总结(通过ArrayList来说明fail-fast的原理、解决办法)

概要 前面,我们已经学习了ArrayList.接下来,我们以ArrayList为例,对Iterator的fail-fast机制进行了解.内容包括::1 fail-fast简介2 fail-fast示例3 fail-fast解决办法4 fail-fast原理5 解决fail-fast的原理 转载:http://www.cnblogs.com/skywang12345/p/3308762.html 1 fail-fast简介 fail-fast 机制是java集合(Collection)中的一种错误