ArrayList和LinkedList的初始化以及扩容机制的源码分析

ArrayList源码分析

ArrayList的类图结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GeM0V8nd-1603712128865)(C:\Users\hp\AppData\Roaming\Typora\typora-user-images\image-20201026141056486.png)]

初始操作

ArrayList中定义的final常量

 /**
       Default initial capacity.
       默认初始化容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    private static final Object[] EMPTY_ELEMENTDATA = {};

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    transient Object[] elementData; // non-private to simplify nested class access
	//size:数组中实际元素个数
	//length:数组在内存中开辟的地址长度
	// size <= length
    private int size;//默认初始化值 --> 0
空参构造器
public ArrayList() {
        this.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);
}
add方法
第一次调用add()
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;//elementData[size]==e;size++;
        return true;
}
private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)/*calculateCapacity(elementData, minCapacity)==10*/);
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);//10
        }
        return minCapacity;
}

private void ensureExplicitCapacity(int minCapacity/*minCapacity==10*/) {
        modCount++;//java.util.AbstractList protected transient int modCount = 0;

        // overflow-conscious code
        if (minCapacity - elementData.length/*elementData.length==0*/ > 0)
            grow(minCapacity);
}
private void grow(int minCapacity/*minCapacity==10*/) {
        // overflow-conscious code
        int oldCapacity = elementData.length;//oldCapacity==0
        int newCapacity = oldCapacity + (oldCapacity >> 1);//newCapacity==0
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;//newCapacity==10
        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);
}
第二次调用add()
 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!  size + 1==2  
        elementData[size++] = e;
        return true;
}
private void ensureCapacityInternal(int minCapacity/*minCapacity==2*/) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)/*calculateCapacity(elementData, minCapacity)==2*/);
}


private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;//minCapacity==2
}
private void ensureExplicitCapacity(int minCapacity/*minCapacity==2*/) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)//2-10<0,不用扩容
            grow(minCapacity);
}
第十一次调用add()
public boolean add(E e) {
      ensureCapacityInternal(size + 1);  // Increments modCount!!  size + 1==11
      elementData[size++] = e;
      return true;
}
private void ensureCapacityInternal(int minCapacity/*minCapacity==11*/) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    //calculateCapacity(elementData, minCapacity)==11
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity/*minCapacity==11*/) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)//11-10>0,扩容
            grow(minCapacity);
}
private void grow(int minCapacity/*minCapacity==11*/) {
        // overflow-conscious code
        int oldCapacity = elementData.length;//oldCapacity==10
        int newCapacity = oldCapacity + (oldCapacity >> 1);//newCapacity==10+5
        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);//newCapacity==15
}
扩容机制

扩容的时候按照右移的方式进行扩容,增加数据之前的list长度值右移一位之后再加上增加数据之前的list长度值,即为扩容之后的长度

第一次扩容后长度:15

第二次扩容后长度:22

按照1.5倍的方式进行扩容(int类型自动取正数值:22,所以可以看作是1.5倍扩容)

set方法
public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
}
private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
get方法
public E get(int index) {
        rangeCheck(index);

        return elementData(index);
}
E elementData(int index) {
        return (E) elementData[index];//elementData是最开始定义的数组,按照下标的方式查找
}
remove方法
public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
}
FailFast

快速失败机制,是java集合类应对并发访问在对集合进行迭代过程中,内部对象结构发生变化一种防护措施.这种错误检测的机制为这种有可能发生错误,通过抛出java.util.ConcurrentModificationException 通过检查modCount是否相等

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9LOrkQFe-1603712128867)(C:\Users\hp\AppData\Roaming\Typora\typora-user-images\image-20201026110703568.png)]

LinkedList源码分析

Linked是由双向链表实现的,具有和双向链表一样的优缺点,LinkedList的类图结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ouxq1xkY-1603712128868)(C:\Users\hp\AppData\Roaming\Typora\typora-user-images\image-20201026172802052.png)]

内部结构

通过一个静态内部类来实现节点

private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
}
LinkedList中定义的final常量
transient int size = 0;//链表最初长度:0

transient Node<E> first;

transient Node<E> last;
对LinkedList进行增加操作
push操作

push()是LinkedList中定义的方法

push方法使用头插法插入新的元素节点

linkedList1.push(5);

public void push(E e) {
        addFirst(e);
}
public void addFirst(E e) {
        linkFirst(e);
}
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++;
}
add操作

add()是List中定义的方法

add方法使用尾插法插入新的元素节点

第一次插入时,lastnull,所以lnull;执行first = newNode;把第一次new(final Node newNode = new Node<>(l, e, null))出来的Node节点设置为开始节点

public boolean add(E e) {
        linkLast(e);
        return true;
}

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++;
}
get方法
public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
}
private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
}
插入方法举例
public static void main(String[] args) {
        LinkedList linkedList1 = new LinkedList();
        linkedList1.push(5);
        linkedList1.push(4);
        linkedList1.push(3);
        linkedList1.push(2);
        linkedList1.push(1);
        linkedList1.add(6);
        linkedList1.add(7);
        linkedList1.add(8);
        linkedList1.add(9);
        linkedList1.add(10);
        System.out.println(linkedList1.get(0));//结果为1
    }

push是头插法,先插入的在后面;add是尾插法,先插入的在前面,

上述代码执行完毕后,链表中数据的存储顺序是1,2,3,4,5,6,7,8,9,10

按照索引从0开始取出对应的值

Vector(已经过时)

Vector和ArrayList类似,Vector中的方法是线程安全的,使用起来不灵活,效率较差,ArrayList是线程不安全的,

使用时可以用Collections工具类中的synchronizedXxx()方法转换成线程安全的,比较灵活,或者使用加锁的方式也可实现线程安全

public static <T> List<T> synchronizedList(List<T> list) {
    return (list instanceof RandomAccess ?
            new SynchronizedRandomAccessList<>(list) :
            new SynchronizedList<>(list));
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值