ArrayList和LinkedList集合底层源码分析

ArrayList底层

ArrayList集合在创建对象后,其实在是在ArrayList类中是继承了一个类和实现了一些接口

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{}

在测试类中我们调用的是ArrayList类的无参构造
先写个测试类:

public static void main(String[] args) {
		ArrayList<String> list= new ArrayList();
		list.add("111");
		list.add("222");
		for (String str : list) {
			System.out.println(str);
		}
	}

但是在ArrayList类中,我发现该无参构造又继续调用了本类的有参构造
无参构造:

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 {
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

从无参构造中发现常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋给了变量elementData ,于是好奇的想知道该常量的声明,通过定位发现:

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

这是一个封装的Object数组中的静态常量,并且该常量没有值,通过再次定位找到elementData代码:

transient Object[] elementData;

transient修饰的变量的elementData不被序行化(暂且先记着,后续再提)
到了这里不难发现,一个没有值的常量赋给了elementData,所以elementData也是没有值的
再看下一个:

private int size;

此时的size默认为0(切记)
回到测试类:

list.add("111");

由此时的add定位到ArrayList类的:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  //扩容, 因为size是没有值的,加1之后size的值为1,然后执行语句
    elementData[size++] = e;
    return true;
}

ensureCapacityInternal可以跳转到数组扩容的方法代码:

private void ensureCapacityInternal(int minCapacity) {
   if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
   }
   ensureExplicitCapacity(minCapacity);
}

其中:

private static final int DEFAULT_CAPACITY = 10;

①判断是否相等,如果elementDataDEFAULTCAPACITY_EMPTY_ELEMENTDATA两值相同,则将得到的值放入判断执行代码块中Math.max()将方法中的最大值赋给minCapacity;②如果两值不相等,则直接调用ensureExplicitCapacity方法,我通过该方法定位到下面扩容代码:

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    if (minCapacity - elementData.length > 0)//如果条件符合,则执行扩容语句
    	grow(minCapacity);
}

但是我发现扩容也只是调用了grow方法,于是再次定位到:

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;	//数组的长度赋给旧数组的长度
    int newCapacity = oldCapacity + (oldCapacity >> 1);	//旧数组的值+旧数组一半的值=新数组的长度
    if (newCapacity - minCapacity < 0)	//如果新数组长度减去现有的数组长度小于0
        newCapacity = minCapacity;	//则现有长度就是新数组的长度(扩容失败)
    if (newCapacity - MAX_ARRAY_SIZE > 0)//如果新数组长度减去最大数组长度大于0
        newCapacity = hugeCapacity(minCapacity);//则最大值长度就是新数组的长度
    elementData = Arrays.copyOf(elementData, newCapacity);
}

突然发现,这才是真正执行扩容的底层

当然我们也可以在创建对象的时候,就声明数组的长度,则此时用到的就是ArrayList的有参构造了

ArrayList<String> list= new ArrayList<>(20);//我先设定长度为20
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);
    }
}

你可能感兴趣的:(javaee)