java源码分析之ArrayList源码分析,ArrayList是常用的集合框架类之一。现在来先简单分析它的源码,占坑先。
构造函数 1 2 3 4 5 6 7 8 /** * Constructs an empty list with an initial capacity of ten. */ 表示构建一个数组,长度为10 public ArrayList() { //DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个Object类型数组的引用 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
常用的方法 1,添加元素
1 2 3 4 5 6 7 8 public boolean add(E e) { //modCount加1 modCount++; // add(e, elementData, size); return true; } ``
private void add(E e, Object[] elementData, int s) { // if (s == elementData.length) elementData = grow(); elementData[s] = e; size = s + 1; }
private Object[] grow() { return grow(size + 1); }
private Object[] grow(int minCapacity) { return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity)); }
private int newCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity <= 0) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) return Math.max(DEFAULT_CAPACITY, minCapacity); if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return minCapacity; } return (newCapacity - MAX_ARRAY_SIZE <= 0) ? newCapacity : hugeCapacity(minCapacity); }
public static T[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); }
1 copyOf(U[] original, int newLength, Class<? extends T[]> newType)
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings(“unchecked”) T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
1 2 3 分析: 以上就是add()方法走的流程,这是基于JDK 11.0.2的。 简而言之就是调用无参的构造函数会创建一个大小为0的Object型数组,
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
1 而DEFAULTCAPACITY_EMPTY_ELEMENTDATA就是一个大小为0的Object数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
1 在新增了一个元素的时候,逐步调用会调用到grow()函数,grow()又继续调用grow(int minCapacity)函数,grow(int minCapacity)返回一个Object类型的数组,这个数组又是怎么生成以及大小是什么呢?这时候到copyOf(T[] original, int newLength)方法:Arrays.copyOf(elementData,newCapacity(minCapacity));第一个参数先不看,第二个参数是newCapacity(minCapacity),返回一个int型的值,这个值是多少呢?这就到了newCapacity(int minCapacity)方法,minCapacity是grow(int minCapacity)中minCapacity传入的,而grow(int minCapacity)是被grow()调用的,传入的参数是size + 1,size正是数组中元素的个数,添加第一个元素的时候size还是为0,所以这里grow(size + 1)的size为0,size + 1为1,也就是minCapacity的值为1,newCapacity(minCapacity)中的minCapacity为1,而初始化数组就是在调用newCapacity(int minCapacity)函数的时候,看代码:
private int newCapacity(int minCapacity) { // overflow-conscious code //oldCapacity = 0 int oldCapacity = elementData.length; //newCapacity = 0 int newCapacity = oldCapacity + (oldCapacity >> 1); //满足这个条件 if (newCapacity - minCapacity <= 0) { //满足这个条件 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) //minCapacity值为1,所以这里显然返回DEFAULT_CAPACITY的值 return Math.max(DEFAULT_CAPACITY, minCapacity); if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return minCapacity; } return (newCapacity - MAX_ARRAY_SIZE <= 0) ? newCapacity : hugeCapacity(minCapacity); }
1 return Math.max(DEFAULT_CAPACITY, minCapacity);DEFAULT_CAPACITY的值是10,是一个常量。所以这样就生成了一个初始容量大小为10的数组。紧接着把第一个元素赋值给数组的第一个位置。
elementData[s] = e;
1 这样就完成初始化了,jdk这样改进后能或多或少节约一点资源,这和HashMap初始化一样,在添加了元素才会在内存开辟空间生成默认大小的数组,一开始是生成了一个引用。比如HashMap的默认构造函数:
public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted }
1 并没有数组实例,只是确认了加载因子。调用了put方法添加元素进去的时候再初始化创建数组。put方法代码:
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 ``` final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; //(tab = table) == null 为true,所以执行1处的代码 if ((tab = table) == null || (n = tab.length) == 0) // resize(), n = (tab = resize()).length;//1 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
执行resize()方法,生成一个大小为16,加载因子为0.75的Node数组。
2,删除元素 1 2 3 4 5 6 7 8 9 public E remove(int index) { Objects.checkIndex(index, size); final Object[] es = elementData; @SuppressWarnings("unchecked") E oldValue = (E) es[index]; fastRemove(es, index); return oldValue; }
3,修改元素 1 2 3 4 5 6 7 8 9 10 public E set(int index, E element) { //检查是否越界 Objects.checkIndex(index, size); //找到要覆盖的元素 E oldValue = elementData(index); //覆盖这个值 elementData[index] = element; //返回旧值 return oldValue; }
查询 不同修改modCount,相对于增删效率要高一些
1 2 3 4 5 6 public E get(int index) { //检查是否越界 Objects.checkIndex(index, size); // return elementData(index); }
清空元素 1 2 3 4 5 6 public void clear() { modCount++; final Object[] es = elementData; for (int to = size, i = size = 0; i < to; i++) es[i] = null; }
包含某个元素 1 2 3 4 //返回一个boolean值,可知indexOf(o)的值大于等于0方法返回的值就为true,就说明包含该元素 public boolean contains(Object o) { return indexOf(o) >= 0; }
indexOf方法
1 2 3 4 public int indexOf(Object o) { // return indexOfRange(o, 0, size); }
indexOfRange方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 //返回一个int值,从start到end范围内,对应到上面的代码就是从0到list列表的大小(size)。 int indexOfRange(Object o, int start, int end) { Object[] es = elementData; //如果o为null, if (o == null) { for (int i = start; i < end; i++) { //注意,ArrayList是可以添加null元素的,且可以添加多个,如果列表中有null //元素,找到一个就返回,返回该元素的下标,它当然大于等于0,所以此时 //indexOfRange(o, 0, size)返回值大于等于0,走到最后indexOf(o)也是大于等 //于0,所以返回true。 if (es[i] == null) { return i; } } } //否则,也就是o不为null, else { for (int i = start; i < end; i++) { //如果o和数组中某个元素相等,返回该元素下标,最终contains也是返回true if (o.equals(es[i])) { return i; } } } //都不满足以上条件,返回-1,小于0,所以contains方法返回false return -1; }
判空 这里很简单,就是看size是否为0,是就返回true,否则返回false
1 2 3 public boolean isEmpty() { return size == 0; }
迭代器 Iterator 1 2 3 public Iterator<E> iterator() { return new Itr(); }