List 实现类源码阅读


List 集合

ArrayList

  • ArrayList 底层使用数组,数组有天然的索引,根据索引获取数组时间复杂度 o(1)
  • 删除元素,如果是最后一个元素时间复杂度为 o(1),如果不是最后一个元素,时间复杂度 o(m-n),此外涉及数组内容的拷贝,性能相对于 LinkedList 差点

构造方法

// 默认构造方法构造一个空数组对象
private static final Object[] 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);
    }
}

// 无参构造方法
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

// 指定集合构造
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

添加元素

 // 添加元素,默认在数组尾部添加
 public boolean add(E e) {
     ensureCapacityInternal(size + 1);  // Increments modCount!!
     elementData[size++] = e;
     return true;
 }

// 添加元素,指定位置,
// 如果列表第一个位置添加元素,然后直接指定第三个位置添加,这样会报错
 public void add(int index, E element) {
     rangeCheckForAdd(index);

     ensureCapacityInternal(size + 1);  // Increments modCount!!
     System.arraycopy(elementData, index, elementData, index + 1,
                      size - index);
     elementData[index] = element;
     size++;
 }

// 添加元素时,确保列表容量
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

// 计算列表容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    // 如果是默认空数组,返回 DEFAULT_CAPACITY = 10
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
         return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    // 如果不是,返回最小列表大小
    return minCapacity;
}

// 确保列表容量,判断是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

	// 比较<列表大小>和<列表容量> 大小,如果列表大小(size) 大于 列表容量
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        // 数组扩容
        grow(minCapacity);
}

// 列表扩容  (minCapacity 是当前数组元素总和)
private void grow(int minCapacity) {
    // overflow-conscious code
    // 元数组长度
    int oldCapacity = elementData.length;
    // >> 1 相当于除以 2,1.5 倍扩容
    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);
}


删除元素

// 根据索引删除元素
public E remove(int index) {
    // 如果索引大于列表的大小,抛异常
    rangeCheck(index);

    modCount++;
    // 拿出旧的元素
    E oldValue = elementData(index);
	
	// 判断列表元素是否需要移动
    int numMoved = size - index - 1;
    // 如果大于0 说明列表的元素需要移动
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    // 将元素置空,让 GC 回收
    elementData[--size] = null; // clear to let GC do its work

	// 返回旧的元素
    return oldValue;
}

// 根据对象删除元素
public boolean remove(Object o) {
    if (o == null) {
        // 如果元素为空,遍历判断元素是否为空,然后删除
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
    	// 如果元素不为空,遍历比较相关
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

修改元素

// 指定索引位置和元素
public E set(int index, E element) {
    // 如果索引大于列表的大小,抛异常
    rangeCheck(index);
	// 拿出旧的值
    E oldValue = elementData(index);
    // 值覆盖
    elementData[index] = element;
    // 返回旧值
    return oldValue;
}

查找元素

public E get(int index) {
    // 如果索引大于列表的大小,抛异常
    rangeCheck(index);
	// 根据索引获取数组的元素
    return elementData(index);
}

LinkedList

  • 底层是双向链表,获取数据的时候性能相对 ArrayList 性能差点
  • 因为是一个双向链表,所以在添加和删除元素的时候只需要处理相关的一个或者两个元素,效率相对ArrayList 稍微好点

构造方法

// 构造一个空的列表
public LinkedList() {
}

// 指定集合构造
public LinkedList(Collection<? extends E> c) {
   this();
   addAll(c);
}

添加方法

// 添加元素
public boolean add(E e) {
    linkLast(e);
    return true;
}

// 在链表尾部添加元素1
void linkLast(E e) {
    // 尾部元素
    final Node<E> l = last;
    // 将当前元素实例化出 Node
    final Node<E> newNode = new Node<>(l, e, null);
    // 最后节点设置成 newNode
    last = newNode;
    // 尾节点为空,当前元素给第一个节点
    if (l == null)
        first = newNode;
    // 尾部为空,新节点给到最后点的下一个节点
    else
        l.next = newNode;
    // 列表大小++
    size++;
    modCount++;
}

// 指定位置添加元素
public void add(int index, E element) {
    // 校验索引的大小
    checkPositionIndex(index);

	// 如果索引在最后,直接加在最后一个节点
    if (index == size)
        linkLast(element);
    // 如果不是在最后,调用 node(index) 和 linkBefore()
    else
        linkBefore(element, node(index));
}

// 根据索引获取指定的元素
Node<E> node(int index) {
	// 校验索引是否合法,源代码已经取消
    // assert isElementIndex(index);

    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

// 在列表的前面添加元素  e -> 新添加元素   succ -> 索引对应的元素
void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        // 索引对应元素的前节点
        final Node<E> pred = succ.prev;
        // 实例化新节点 newNode -> (前节点,当前节点元素,后节点)
        // 1 -> 2 -> 3,比如在 1 的位置插入元素 6,那么实例化新节点: 1,6,2 (pred,e,succ)
        final Node<E> newNode = new Node<>(pred, e, succ);
        // 原索引节点的前节点为新插入的元素,既 2 节点的前节点为 6
		succ.prev = newNode;
		// 如果前节点为空,说明是第一个添加
        if (pred == null)
        	// 新节点给第一个元素
            first = newNode;
        // 如果前节点不为空,说明不是第一个添加
        else
            // 将新节点赋值给 当前索引节点的前节点的下一个节点
            // 新节点:6,当前节点:2,2的前节点为 1,现在把新节点 6 赋值给节点1的 next
            pred.next = newNode;
        // 列表大小 ++
        size++;
        modCount++;
    }

删除元素

// 根据索引删除元素
public E remove(int index) {
    checkElementIndex(index);
    // node(index) 根据索引获取当前节点
    // unlink() 移除元素
    return unlink(node(index));
}

// 检查元素索引
private void checkElementIndex(int index) {
    if (!isElementIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

// 索引要大于0,而且小于链表大于
private boolean isElementIndex(int index) {
   return index >= 0 && index < size;
}

// 移除链表元素
E unlink(Node<E> x) {
	
	// 假设有一个这样的链表,要删除 2这个节点
	// 1 -> 2 -> 3     

    // 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 {
    	// 当前节点的 前节点的next 指向 当前节点的next节点
    	// 1 节点的next 指向 3
        prev.next = next;
        x.prev = null;
    }

	// 如果下节点为空
    if (next == null) {
        // 把前节点赋值给最后节点
        last = prev;
    } else {
    	// 后节点的前节点执行前节点
    	// 3的前节点指向1的后节点
        next.prev = prev;
        x.next = null;
    }
	
	// 元素置空
    x.item = null;
    // 列表大小--
    size--;
    modCount++;
    return element;
}

// 根据对象删除元素
public boolean remove(Object o) {
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}

修改元素

// 修改链表元素
public E set(int index, E element) {
    // 检查索引
    checkElementIndex(index);
    // 获取当前索引元素
    Node<E> x = node(index);
    // 获取旧的值
    E oldVal = x.item;
    // 修改
    x.item = element;
    // 返回
    return oldVal;
}

查找元素

public E get(int index) {
    // 检查索引
    checkElementIndex(index);
    // 根据索引获取元素
    return node(index).item;
}

// 根据索引获取 Node 节点
Node<E> node(int index) {
    // assert isElementIndex(index);

	// 1 -> 2 -> 3 -> 4 -> 5
	
	// 索引 小于 链表大小除以2
    if (index < (size >> 1)) {
    	// 从头节点开始
        Node<E> x = first;
        // 遍历到索引位置的节点,返回节点
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } 
	// 索引 大于 链表大小除以2
	else {
		// 从尾部节点开始
        Node<E> x = last;
        // 开始遍历到索引节点
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

Vector 集合

  • Vector 相当于是一个线程安全的 ArrayList,底层也是数组,但是里面的方法基本都使用 synchronized,性能相对较差
  • 现在使用 Vector 基本很少了,对源码感兴趣的可以尝试阅读一下,和 ArrayList 的实现比较类似

CopyOnWriteArrayList

添加元素

/** 每个对象都有的锁对象 */
final transient ReentrantLock lock = new ReentrantLock(); 

// 添加元素
public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    // 上锁
    lock.lock();
    try {
    	// 获取列表元素
        Object[] elements = getArray();
        // 原数组长度
        int len = elements.length;
        // 将旧的数据拷贝到新列表
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        // 新元素赋值咋最后
        newElements[len] = e;
        // 新数组赋值
        setArray(newElements);
        return true;
    } finally {
    	// 释放锁
        lock.unlock();
    }
}

// 指定索引位置添加元素
public void add(int index, E element) {
    final ReentrantLock lock = this.lock;
    // 上锁
    lock.lock();
    try {
    	// 获取数组元素
        Object[] elements = getArray();
        // 数组长度
        int len = elements.length;
        // 校验索引
        if (index > len || index < 0)
            throw new IndexOutOfBoundsException("Index: "+index+
                                                ", Size: "+len);
        Object[] newElements;
        // 要移动的元素偏移量
        int numMoved = len - index;
        // 为0不需要移动
        if (numMoved == 0)
            newElements = Arrays.copyOf(elements, len + 1);
        else {
        	// 数组拷贝
            newElements = new Object[len + 1];
            System.arraycopy(elements, 0, newElements, 0, index);
            System.arraycopy(elements, index, newElements, index + 1,
                             numMoved);
        }
        // 新元素给到对应的位置
        newElements[index] = element;
        // 设置数组
        setArray(newElements);
    } finally {
    	// 释放锁
        lock.unlock();
    }
}

删除元素

// 根据索引删除元素
public E remove(int index) {
    final ReentrantLock lock = this.lock;
    // 获取锁
    lock.lock();
    try {
    	// 获取数组元素
        Object[] elements = getArray();
        // 数组长度
        int len = elements.length;
        // 获取旧的值
        E oldValue = get(elements, index);
        // 计算移动元素个数
        int numMoved = len - index - 1;
        // 为0说明删除的是最后一个元素
        if (numMoved == 0)
            setArray(Arrays.copyOf(elements, len - 1));
        // 不为0,说明不是最后一个元素
        else {
            Object[] newElements = new Object[len - 1];
            System.arraycopy(elements, 0, newElements, 0, index);
            System.arraycopy(elements, index + 1, newElements, index,
                             numMoved);
            setArray(newElements);
        }
        return oldValue;
    } finally {
        lock.unlock();
    }
}

// 根据对象删除元素
public boolean remove(Object o) {
    Object[] snapshot = getArray();
    int index = indexOf(o, snapshot, 0, snapshot.length);
    return (index < 0) ? false : remove(o, snapshot, index);
}

修改元素

// 修改数组
public E set(int index, E element) {
    final ReentrantLock lock = this.lock;
    // 获取锁
    lock.lock();
    try {
        // 获取数组元素
        Object[] elements = getArray();
        // 获取旧的值
        E oldValue = get(elements, index);

		// 旧的值与新的值不相等
        if (oldValue != element) {
            // 数组长度
            int len = elements.length;
            // 数组拷贝,值还是原来的值
            Object[] newElements = Arrays.copyOf(elements, len);
            // 给最新的值到指定位置
            newElements[index] = element;
            // 数组赋值
            setArray(newElements);
        } else {  // 值相等,不操作
            // Not quite a no-op; ensures volatile write semantics
            setArray(elements);
        }
        return oldValue;
    } finally {
    	// 释放锁
        lock.unlock();
    }
}

查找元素

// 根据索引获取元素
public E get(int index) {
        return get(getArray(), index);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tytler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值