List源码详解

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值