深入了解List集合(源码解读)

这篇文章讲的是List集合的三个子类:ArrayList LinkedList Vector

在这里插入图片描述
将会深入到源码的层面去了解它们的方法,从而对他们产生更深的理解,并且会对他们三者进行比较,分析什么时候使用哪个类比较好

1.ArrayList
1.1 ArrayList属性
在这里插入图片描述
上图是ArrayList的一些定义的常量,其中

private static final int DEFAULT_CAPACITY = 10; 说明了它的初始容量为10

private static final Object[] EMPTY_ELEMENTDATA = {}; 当ArrayList的容量被设置为为0时将会初始化为这个空数组

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 如果没有指定容量默认会初始化的是这个数组

transient Object[] elementData; ArrayList中的元素实际上是被保存在这个数组中,它的长度就是ArrayList的容量,当有元素添加进一个空的ArrayList中时,该ArrayList的容量将被扩容成DEFAULT_CAPACITY

从这里可以看出,ArrayList的底层就是数组,但是它可以进行扩容,所以我们使用的时候感觉他是一个长度可变的数组,扩容在后面add( ) 方法那块我会给分析分析

1.2 ArrayList构造方法
在这里插入图片描述
看到ArrayList有三种构造方法:1.指定容量2.无参构造3.根据Collection对象构造

在指定容量的构造方法中,容量为0的话,将会初始化为空数组EMPTY_ELEMENTDATA
,否则初始化为指定的容量
在无参构造方法中,将会初始化为空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA
在参数为Collection类的构造方法中,则会根据Collection中的元素构造出一个ArrayList

1.3 add( ) 方法
在这里插入图片描述
(1)ArrayList的add( ) 方法跟扩容有关系,先来瞧瞧前面那个add(E e) ,它就两行,先调用了一个ensureCapacityInternal(size + 1);看名字大概意思是确定内部容量,然后就把元素添加进数组中,点进去看
在这里插入图片描述
里面调用了一个另一个方法:
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity))
大概意思是确定明确的容量,这个方法的参数是由
calculateCapacity(elementData, minCapacity)
计算得出来的,点进去看
在这里插入图片描述
顾名思义,就是计算所需的容量,如果容量是零的话(第一次添加元素),那么就将DEFAULT_CAPACITY和 刚刚传进来的size+1 中较大者作为明确地容量返回,否则直接返回 size+1 也就是minCapacity

再来看ensureExplicitCapacity()
在这里插入图片描述
第一行的modCount 是用来记录记录集合变化次数的变量。作用是在使用迭代器Iterator对集合进行遍历时,用modCount来判断集合内数据没有发生变化,否则会抛出异常。
重要的是后面如果所需的最小容量大于当前容量,就调用grow ( minCapacity ) 进行扩容,点进去看
在这里插入图片描述
第二行的效果就是扩容成旧容量的1.5倍,然后下面是如果扩容后仍然小于minCapacity ,那么就将minCapacity作为新容量。但是如果扩容之后比 MAX_ARRAY_SIZE 还大,那么就调用 hugeCapacity( minCapacity ) ,顾名思义,生成一个超大容量作为新容量,其实就是int的最大值,最后调用Arrays.copyOf( ) 方法将原数组的元素复制到新数组中去,扩容结束

来小小总结一下:
1.先确定添加一个元素所需要的最小容量
2.判断是否要扩容,否的话直接添加
3.扩容首先将新容量定为旧容量的1.5倍
4.如果还不够,就将所需的最小容量作为新容量
5.判断新容量是否大于数组的最大容量(其实就是Integer.MAX_VALUE - 8)
6.是则将Integer.MAX_VALUE 作为新容量
7.调用coprOf( ) 方法将元素复制到新数组中去

(2)接下来看另一个根据下标添加的方法add(int index, E element)
在这里插入图片描述
.首先第一行检查下标是否越界,然后就是熟悉的确定容量,最后调用arraycopy( )方法来完成添加,这个arraycopy( )方法是一个native方法,也就是说它不是用Java写的

1.4 get方法
在这里插入图片描述
get方法很简单,就两行,首先检查下标是否越界,然后返回相应的元素

1.5 set方法

set方法首先检查下标是否越界,然后将旧元素取出并替换为新元素,最后返回旧元素

1.6 remove方法
在这里插入图片描述
remove方法仍然是先检查下标是否越界,然后计算出数组需要左移的长度,调用arraycopy()方法完成左移

1.7 ensureCapacity()方法
在这里插入图片描述

最后提一嘴ensureCapacity() 方法,这个方法是在知道ArrayList将要add进很多元素之前使用的,直接指定一个所需的最小容量,然后方法中调用ensureExplicitCapacity() 来进行扩容,直接扩容到指定的大小,这样就避免了在连续的add 时一次又一次地扩容,效率低下

  1. Vector

Vector 与 ArrayList 的共同点在于它们底层都是数组,最大的区别就在于Vector 它是线程安全的了,但是它是一个很老旧的类了,已经不被建议使用了
Vector 的效率十分低下,主要原因在于它给所有的方法都加上了synchronize修饰
如果没有线程安全的需求,一般都建议使用ArrayList,如果想要ArrayList实现同步,可以使用Collections的方法:List list = Collections.synchronizedList(new ArrayList(…));,就可以实现同步了

  1. LinkedList
    有空补上
  2. 总结对比
    有空补上

猜你喜欢

转载自blog.csdn.net/weixin_41660213/article/details/107947592
今日推荐