List源码详解

来源:互联网 发布:java游戏源码教程 编辑:程序博客网 时间:2024/06/05 21:18

List源码比较简单,里面就是定义了一些方法。


List源码600行

读取(get),插入(add),删除(remove),修改(set),也可批量增加(addAll),删除(removeAll,retainAll),获取(subList)。
还有一些判定操作:包含(contains[All]),相等(equals),索引(indexOf,lastIndexOf),大小(size)。还有获取元素类型数组的操作:toArray()


ArrayList源码1172行

ArrayList是基于数组实现的,是一个动态数组(长度可变的数据结构,允许null当元素,默认长度是10,一次增长0.5倍,其容量为原来的1.5倍。

ArrayList提供了三种方式的构造器:

1、可以构造一个默认初始容量为10的空列表;

2、构造一个指定初始容量;

3、构造一个包含指定collection的元素的列表。


// ArrayList带容量大小的构造函数。public ArrayList(int initialCapacity) {        super();        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);        // 新建一个指定容量的数组</span>        this.elementData = new Object[initialCapacity];    }    // ArrayList无参构造函数。默认容量是10。    public ArrayList() {        super();        this.elementData = EMPTY_ELEMENTDATA;    }    //构造方法传入一个Collection, 则将Collection里面的值copy到arrayList    public ArrayList(Collection<? extends E> c) {        elementData = c.toArray();        size = elementData.length;        // c.toArray might (incorrectly) not return Object[] (see 6260652)        if (elementData.getClass() != Object[].class)            elementData = Arrays.copyOf(elementData, size, Object[].class);}

调整数组容量:

ensureCapacity(intminCapacity): 从上面介绍的向ArrayList中 存储元素的代码中,我们看到, 每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容,以满足添加数 据的需求。数组扩容通过一个公开的方法ensureCapacity(intminCapacity)来实现。在实际添加大量元素前,我也可以使用ensureCapacity来手动增加ArrayList实例的容量,以减少递增式再分配的数量。另外扩容一次其容量为原来的1.5倍。

public void ensureCapacity(int minCapacity) {        if (minCapacity > 0)            ensureCapacityInternal(minCapacity);}

问题:

数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。所以在初始化ArrayList的时候尽量预算下大致的容量需求,降低频繁调整容量的开销。

void trimToSize() : 将底层数组的容量调整为当前列表保存的实际元素的大小的功能。
由于elementData的长度会被拓展,size标记的是其中包含的元素的个数。所以会出现size很小但 elementData.length很大的情况,将出现空间的浪费。trimToSize将返回一个新的数组给elementData,元素内容保持不 变,length和size相同,节省空间。


public void trimToSize() {      modCount++;      int oldCapacity = elementData.length;      if (size < oldCapacity) {         elementData = Arrays.copyOf(elementData, size);      }}

LinkedList源码1138行

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。链表主要包含单向链表,单向循环链表,双向链表,双向循环链表。LinkedList是属于双向链表,下图是包含头结点和尾节点的双向链表。

LinkedList底层的数据结构是基于双向链表的,且头结点中不存放数据,如下:


既然是双向链表,那么必定存在一种数据结构——我们可以称之为节点,节点实例保存业务数据,前一个节点的位置信息和后一个节点位置信息,如下图所示:



元素添加步骤:

第一步:调用无参构造方法,创建LinkedList实例

第二步:初始化一个预添加的Entry实例(newEntry)。

第三步:调整新加入节点和头结点(header)的前后指针。



LinkedList提供了两个构造方法:


public LinkedList() {     header.next = header.previous = header;}public LinkedList(Collection<? extends E> c) {    this();    addAll(c);}

删除数据remove()

由于删除了某一节点因此调整相应节点的前后指针信息,如下:

e.previous.next = e.next;//预删除节点的前一节点的后指针指向预删除节点的后一个节点。 

e.next.previous = e.previous;//预删除节点的后一节点的前指针指向预删除节点的前一个节点。


Vector源码1212行

Vector:ArrayList的前身,数组结构,线程安全,速度慢

Vector构造函数。默认容量是10。一次增长原来的一倍。

public Vector() {        this(10);}

其他分析,请参考ArrayList

1 0
原创粉丝点击