本文共 19148 字,大约阅读时间需要 63 分钟。
// jdk1.6的/** Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this(10);}jdk1.7的,相对1.6版本,引入了一个新的常量EMPTY_ELEMENTDATA,它是一个空数组,因此容量为0。
// jdk1.7的/** Shared empty array instance used for empty instances. */private static final Object[] EMPTY_ELEMENTDATA = {};.../** Constructs an empty list with an initial capacity of ten. */public ArrayList() { super(); this.elementData = EMPTY_ELEMENTDATA;}jdk1.8的,相对1.7版本,又引入了一个新的常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA ,它也是一个空数组,因此容量也为0。至于两个空数组有什么区别,看下面一点说的。
/** Shared empty array instance used for empty instances. */private static final Object[] EMPTY_ELEMENTDATA = {};/** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};.../** Constructs an empty list with an initial capacity of ten. */public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
// 1.6public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity];}// 1.7 跟1.6的一样public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity];}// 1.8public 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); }}678三个版本的这个构造方法的实际行为基本一致:如果initialCapacity >= 0,把底层数组elementData赋值为一个大小为initialCapacity的数组,数组的所有元素都是默认值null。1.8稍微进行了一点优化,也是赋值为空数组,但是重用了常量对象。
// jdk1.6,两个构造的区别很明显public class TestArrayList { public static void main(String[] args) { Listla = new ArrayList (0); // la.elementData = new Object[0], la.elementData.length = 0 la.add("111"); // la.elementDate.length = 1,这里一次性扩容了1个,后续再按照通用扩容策略执行扩容操作 List lb = new ArrayList (); // lb.elementData = new Object[10], lb.elementData.length = 10 lb.add("111"); // lb.elementDate.length = 10,这里没有进行扩容,后续再按照通用扩容策略执行扩容操作 }}// jdk1.7,两个构造在第一次进行添加时才看得出区别public class TestArrayList { public static void main(String[] args) { List la = new ArrayList<>(0); // la.elementData = new Object[0], la.elementData.length = 0 la.add("111"); // la.elementDate.length = 1,这里一次性扩容了1个,后续再按照通用扩容策略执行扩容操作 List lb = new ArrayList<>(); // lb.elementData = EMPTY_ELEMENTDATA, lb.elementData.length = 0 lb.add("111"); // lb.elementDate.length = 10,这里一次性扩容了10个,后续再按照通用扩容策略执行扩容操作 }}// jdk1.8,同1.7public class TestArrayList { public static void main(String[] args) { List la = new ArrayList<>(0); // la.elementData = EMPTY_ELEMENTDATA, la.elementData.length = 0 la.add("111"); // la.elementDate.length = 1,这里一次性扩容了1个,后续再按照通用扩容策略执行扩容操作 List lb = new ArrayList<>(); // lb.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA, lb.elementData.length = 0 lb.add("111"); // lb.elementDate.length = 10,这里一次性扩容了10个,后续再按照通用扩容策略执行扩容操作 }}
// jdk 1.6public ArrayList(Collection 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);}// jdk 1.7public ArrayList(Collection 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);}// jdk 1.8public ArrayList(Collection c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; }}
// 手动扩容方法(可以外部调用,不过大多数情况都是List = new ArrayList<>(),这样是调用不到这个方法的)// 这个方法只是简单区别下list是不是通过 new ArrayList() 来创建的,这一点前面说了// 如果是,则尝试最小扩容10个,不是则尝试扩容指定个,具体也是通过内部扩容方法完成容量确保public void ensureCapacity(int minCapacity) { int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) // any size if not default element table ? 0 // larger than default for default empty table. It's already // supposed to be at default size. : DEFAULT_CAPACITY; if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); }}// 下面是内部扩容相关的几个方法的代码private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity);}private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code 考虑int型溢出 if (minCapacity - elementData.length > 0) grow(minCapacity);}private void grow(int minCapacity) { // overflow-conscious code 考虑int型溢出 int oldCapacity = elementData.length; 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);}private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow int型溢出,直接报错 throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;}
public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }}
// 此方法就是一个简单的数组批量删除方法,并且删除后剩余的元素相对顺序不变,且全部往前移动// 之所以使用try-fianlly是因为c.contains可能会抛出异常(c == null,或者实现类中不允许null),导致ArrayList没有能更新size以及对底层数组进行整理,// 使用finally可以保证保证这一点,并且与父类AbstractCollection中已经实现的removeAll/retainAll方法的行为的一致性// 通过finally中的代码可以看出,这些没有进行判断的元素会全部保留。private boolean batchRemove(Collection c, boolean complement) { final Object[] elementData = this.elementData; int r = 0, w = 0; boolean modified = false; try { for (; r < size; r++) if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } if (w != size) { // clear to let GC do its work for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w; modified = true; } } return modified;}
publicT[] toArray(T[] a) { if (a.length < size) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a;}
public class TestArrayList { public static void main(String[] args) { ListsList = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); // 推荐使用空数组 String[] s0 = {}; System.err.println("s0 = " + Arrays.toString(sList.toArray(s0))); // s0 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // 也可以使用等长数组 String[] s10 = new String[sList.size()]; System.err.println("s10 = " + Arrays.toString(sList.toArray(s10))); // s10 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // 除非你清楚,否则不要像下面这么做,因为s20[10]被此方法设置为null String[] s20 = new String[20]; s20[10] = "10"; s20[11] = "11"; s20[12] = "12"; System.err.println("s20 = " + Arrays.toString(sList.toArray(s20))); // s20 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null, 11, 12, null, null, null, null, null, null, null] }}