Java常见集合之ArrayList深入分析
Java常见集合之ArrayList深入分析
一、继承树
二、ArrayList源码分析
2.1 继承结构和层次关系
![](https://img2020.cnblogs.com/blog/1506592/202004/1506592-20200404183208567-1135805581.png)
2.2 源码分析:
1 /* 2 继承自AbstractList,实现了List、RandomAccess、Cloneable、Serializable接口 3 1)RandomAccess接口:用来快速随机存取,在实现了该接口后,用普通for来遍历,性能更高 4 2)Cloneable接口:实现了该接口,就可以使用Object.Clone()方法了 5 3)Serializable接口:实现了该接口,表明该类可以被序列化 6 */ 7 public class ArrayList<E> extends AbstractList<E> 8 implements List<E>, RandomAccess, Cloneable, java.io.Serializable 9 { 10 //版本号 11 private static final long serialVersionUID = 8683452581122892189L; 12 //缺省容量 13 private static final int DEFAULT_CAPACITY = 10; 14 //缺省空对象数组 15 private static final Object[] EMPTY_ELEMENTDATA = {}; 16 //默认大小的对象数组 17 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 18 //元素数组 19 transient Object[] elementData; 20 //数组的大小 21 private int size; 22 23 //构造方法 24 //无参构造 Constructs an empty list with an initial capacity of ten 25 public ArrayList() { 26 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 27 } 28 29 /** 30 * Constructs an empty list with the specified initial capacity. 31 * 32 * @param initialCapacity the initial capacity of the list 33 * @throws IllegalArgumentException if the specified initial capacity 34 * is negative 35 */ 36 public ArrayList(int initialCapacity) { 37 if (initialCapacity > 0) { 38 this.elementData = new Object[initialCapacity]; 39 } else if (initialCapacity == 0) { 40 this.elementData = EMPTY_ELEMENTDATA; 41 } else { 42 throw new IllegalArgumentException("Illegal Capacity: "+ 43 initialCapacity); 44 } 45 } 46 47 /** 48 * Constructs a list containing the elements of the specified 49 * collection, in the order they are returned by the collection's 50 * iterator. 51 * 52 * @param c the collection whose elements are to be placed into this list 53 * @throws NullPointerException if the specified collection is null 54 */ 55 public ArrayList(Collection<? extends E> c) { 56 elementData = c.toArray(); //转换为数组 57 if ((size = elementData.length) != 0) { //数组长度大于0 58 // c.toArray might (incorrectly) not return Object[] (see 6260652) 59 if (elementData.getClass() != Object[].class) 60 elementData = Arrays.copyOf(elementData, size, Object[].class); 61 } else { 62 // replace with empty array. 63 this.elementData = EMPTY_ELEMENTDATA; 64 } 65 } 66 //总体而言:arrayList的构造方法就是做一件事,初始化一下储存数据的容器, 67 // 其实本质就是一个数组,在其中就叫elementData 68 69 //核心方法 70 /** 71 * Appends the specified element to the end of this list. 72 * 默认直接在末尾添加元素 73 * 74 * @param e element to be appended to this list 75 * @return <tt>true</tt> (as specified by {@link Collection#add}) 76 */ 77 public boolean add(E e) { //elementData=[1,2,3] e=6 78 //确保数组的容量足够 79 ensureCapacityInternal(size + 1); // Increments modCount!! 80 //数组尾部添加元素e 81 elementData[size++] = e; 82 return true; 83 } 84 85 private void ensureCapacityInternal(int minCapacity) { //minCapacity=4 87 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); 88 } 89 90 //计算容量 91 private static int calculateCapacity(Object[] elementData, int minCapacity) {//elementData=[1,2,3],minCapacity=4 92 //如果元素数组等于默认容量的元素数组,就返回DEFAULT_CAPACITY和minCapacity两者的最大值 93 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { 94 return Math.max(DEFAULT_CAPACITY, minCapacity); 95 } 96 //否则就返回minCapacity 97 return minCapacity; //4 98 } 99 100 private void ensureExplicitCapacity(int minCapacity) { //minCapacity=4 101 modCount++; 102 103 // overflow-conscious code 104 /* 105 这里有两种情况: 106 情况一:elementData为空数组,minCapacity=size+1=1,1-0>0,调用grow()进行扩容 107 情况二:elementData不为空数组,minCapacity=size+1,为elementData原始的数组(未调用add方法前), 108 如果length不够用,再调用grow()进行扩容 109 */ 110 if (minCapacity - elementData.length > 0) 111 grow(minCapacity); 112 } 113 114 /** 115 * 增加容量以确保它至少可以容纳由最小容量参数指定的元素数 116 * Increases the capacity to ensure that it can hold at least the 117 * number of elements specified by the minimum capacity argument. 118 * 119 * @param minCapacity the desired minimum capacity 120 */ 121 private void grow(int minCapacity) { 122 // overflow-conscious code 123 //将原始的elementData.length赋给oldCapacity 124 int oldCapacity = elementData.length; 125 //新容量=1.5*oldCapacity 126 int newCapacity = oldCapacity + (oldCapacity >> 1); 127 //如果elementData为空数组,那么oldCapacity和newCapacity都为0,将newCapacity直接赋值为10 128 if (newCapacity - minCapacity < 0) 129 newCapacity = minCapacity; 130 //如果newCapacity超过了最大的容量限制,将调用hugeCapacity()做进一步处理 131 if (newCapacity - MAX_ARRAY_SIZE > 0) 132 newCapacity = hugeCapacity(minCapacity); 133 // minCapacity is usually close to size, so this is a win: 134 //newCapacity确定好了以后,就copyof数组,进行扩容 135 elementData = Arrays.copyOf(elementData, newCapacity); 136 } 137 138 private static int hugeCapacity(int minCapacity) { 139 if (minCapacity < 0) // overflow 140 throw new OutOfMemoryError(); 141 //判断minCapacity是否大于最大的数组容量MAX_ARRAY_SIZE:是,返回Integer.MAX_VALUE(2147483647); 142 //否则返回MAX_ARRAY_SIZE 143 return (minCapacity > MAX_ARRAY_SIZE) ? 144 Integer.MAX_VALUE : 145 MAX_ARRAY_SIZE; 146 } 147 148 /** 149 * 在指定位置插入元素 150 * Inserts the specified element at the specified position in this 151 * list. Shifts the element currently at that position (if any) and 152 * any subsequent elements to the right (adds one to their indices). 153 * 154 * @param index index at which the specified element is to be inserted 155 * @param element element to be inserted 156 * @throws IndexOutOfBoundsException {@inheritDoc} 157 */ 158 public void add(int index, E element) { 159 //检查插入的位置是否合理 160 rangeCheckForAdd(index); 161 162 //插入元素之后,将index之后的元素都往后移一位 163 ensureCapacityInternal(size + 1); // Increments modCount!! 164 System.arraycopy(elementData, index, elementData, index + 1, 165 size - index); 166 elementData[index] = element; 167 size++; 168 } 169 170 /** 171 * 用于add和addAll方法的范围检查 172 * A version of rangeCheck used by add and addAll. 173 */ 174 private void rangeCheckForAdd(int index) { 175 if (index > size || index < 0) 176 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 177 } 178 179 /** 180 * 删除指定位置的元素 181 * Removes the element at the specified position in this list. 182 * Shifts any subsequent elements to the left (subtracts one from their 183 * indices). 184 * 185 * @param index the index of the element to be removed 186 * @return the element that was removed from the list 187 * @throws IndexOutOfBoundsException {@inheritDoc} 188 */ 189 public E remove(int index) { 190 //范围检查 191 rangeCheck(index); 192 193 modCount++; 194 E oldValue = elementData(index); //要删除指定index位置的值 195 196 //计算要移动的位数 197 int numMoved = size - index - 1; 198 if (numMoved > 0) 199 /* 200 public static native void arraycopy(Object src, int srcPos, 201 Object dest, int destPos, 202 int length); 203 Copies an array from the specified source array, beginning at the 204 specified position, to the specified position of the destination array. 205 从源数组的特殊位置开始拷贝到目标数组的特定位置 206 207 System.arraycopy(elementData, index+1, elementData, index, 208 size - index - 1); //size=8,index=5,8-5-1=2,src=[1,2,3,4,5,7,8] 209 */ 210 System.arraycopy(elementData, index+1, elementData, index, 211 numMoved); 212 elementData[--size] = null; // clear to let GC do its work 213 214 return oldValue; 215 } 216 217 /** 218 * 移除list列表中第一次出现的待删除的元素 219 * Removes the first occurrence of the specified element from this list, 220 * if it is present. If the list does not contain the element, it is 221 * unchanged. More formally, removes the element with the lowest index 222 * <tt>i</tt> such that 223 * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> 224 * (if such an element exists). Returns <tt>true</tt> if this list 225 * contained the specified element (or equivalently, if this list 226 * changed as a result of the call). 227 * 228 * @param o element to be removed from this list, if present 229 * @return <tt>true</tt> if this list contained the specified element 230 */ 231 public boolean remove(Object o) { 232 //依次遍历删除 233 if (o == null) { 234 for (int index = 0; index < size; index++) 235 if (elementData[index] == null) { 236 fastRemove(index); 237 return true; 238 } 239 } else { 240 for (int index = 0; index < size; index++) 241 if (o.equals(elementData[index])) { 242 fastRemove(index); 243 return true; 244 } 245 } 246 return false; 247 } 248 //remove函数用户移除指定下标的元素,此时会把指定下标到数组末尾的元素向前移动一个单位, 249 //并把最后一个元素置为null 250 251 /** 252 * 将list表中指定位置的元素替换掉 253 * Replaces the element at the specified position in this list with 254 * the specified element. 255 * 256 * @param index index of the element to replace 257 * @param element element to be stored at the specified position 258 * @return the element previously at the specified position 259 * @throws IndexOutOfBoundsException {@inheritDoc} 260 */ 261 public E set(int index, E element) { 262 //范围检查 263 rangeCheck(index); 264 265 //指定位置的元素值 266 E oldValue = elementData(index); 267 //将elementData的指定位置替换为element 268 elementData[index] = element; 269 return oldValue; 270 } 271 272 /** 273 * 返回在list列表中的指定元素第一次出现的索引值 274 * Returns the index of the first occurrence of the specified element 275 * in this list, or -1 if this list does not contain the element. 276 * More formally, returns the lowest index <tt>i</tt> such that 277 * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, 278 * or -1 if there is no such index. 279 */ 280 public int indexOf(Object o) { 281 if (o == null) { 282 for (int i = 0; i < size; i++) 283 if (elementData[i]==null) 284 return i; 285 } else { 286 for (int i = 0; i < size; i++) 287 if (o.equals(elementData[i])) 288 return i; 289 } 290 return -1; 291 } 292 //从头开始查找元素,可以查找null值 293 294 /** 295 * 返回在list列表中指定位置的元素 296 * Returns the element at the specified position in this list. 297 * 298 * @param index index of the element to return 299 * @return the element at the specified position in this list 300 * @throws IndexOutOfBoundsException {@inheritDoc} 301 */ 302 public E get(int index) { 303 //范围检查,只检查>=size的部分 304 rangeCheck(index); 305 306 return elementData(index); 307 } 308 309 E elementData(int index) { 310 return (E) elementData[index]; 311 } 312 //注意:返回的值都做了向下转型(object->E)处理 313 }
2.3 小结:
1、ArrayList底层就是一个elementData数组,不过跟array相区别的是,它存在一个动态扩容机制
2、由于每次添加、删除元素,都涉及到数组元素的移动,因此效率不高
3、由于ArrayList实现了RandomAccess接口,适合做随机访问,用for循环进行查找元素,效率较高