【小笨鸟看JDK1.7集合源码之二】ArrayList源码剖析
主要是参考大神兰亭风雨的博客;
ArrayList简介
(1) ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。
(2) ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。
(3) ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Cloneable接口,能被克隆。
ArrayList(JDK1.7)源码详细剖析注释
1 package java.util; 2 3 /** 4 * JDK1.7 5 * @author foolishbird_lmy 6 * 7 */ 8 public class ArrayList<E> extends AbstractList<E> 9 implements List<E>, RandomAccess, Cloneable, java.io.Serializable 10 { 11 //自动生成的序列版本号,主要用于版本的兼容问题 12 private static final long serialVersionUID = 8683452581122892189L; 13 14 //默认的容量,用于每次数组的自动扩展 15 private static final int DEFAULT_CAPACITY = 10; 16 17 //定义的一个默认空数组对象 18 private static final Object[] EMPTY_ELEMENTDATA = {}; 19 20 //ArrayList是基于数组结构来实现的,该数组用来实际保存数据,transient这个关键字是声明改变量不能被序列化 21 private transient Object[] elementData; 22 23 //当前集合中实际的元素的个数即大小 24 private int size; 25 26 //带参数的构造函数,initialCapacity,初始化的容量即需要构造的List的大小 27 public ArrayList(int initialCapacity) { 28 super(); 29 if (initialCapacity < 0) 30 throw new IllegalArgumentException("Illegal Capacity: "+ 31 initialCapacity); 32 this.elementData = new Object[initialCapacity]; 33 } 34 35 //无参构造函数初始化,注意是根据默认大小限定为10,即你不传参数时也会构造大小为10的List 36 public ArrayList() { 37 super(); 38 this.elementData = EMPTY_ELEMENTDATA; 39 } 40 41 /* 42 *创建一个包含Collection类型的ArrayList,实际的过程是首先根据Collection中的元素复制一个数组 43 */ 44 public ArrayList(Collection<? extends E> c) { 45 elementData = c.toArray();//返回包含此 collection 中所有元素的数组。 46 size = elementData.length;//数组的长度 47 if (elementData.getClass() != Object[].class)//判断是否为数组类型 48 elementData = Arrays.copyOf(elementData, size, Object[].class);//Arrays工具类,复制数组 49 } 50 //将此 ArrayList 实例的容量调整为列表的当前大小,即根据当前的实际数组元素的长度设置容量 51 public void trimToSize() { 52 modCount++; 53 /*这个参数仔细查了一下,是父类AbstractList中定义了一个int型的属性:modCount,记录了ArrayList结构性变化的次数 54 包括:add()、remove()、addAll()、removeRange()及clear()方法。这些方法每调用一次,modCount的值就加1。 55 主要的作用就是在迭代的时候保持单线程的安全性;只要是容量发生变化这个参数就会自动随着变化 56 */ 57 if (size < elementData.length) { 58 elementData = Arrays.copyOf(elementData, size); 59 } 60 } 61 62 /* 63 如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数. 64 DEFAULT_CAPACITY 默认的最小值10 65 EMPTY_ELEMENTDATA 默认为空 66 */ 67 //这个方法的主要作用是确定当前集合的容量是否足够,minCapacity参数是所需的最小容量,如果小于则扩容 68 public void ensureCapacity(int minCapacity) { 69 //三目运算,如果elementData为空,则minExpand=DEFAULT_CAPACITY=10,否则取0 70 int minExpand = (elementData != EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY; 71 //如果小于则扩容 72 if (minCapacity > minExpand) { 73 ensureExplicitCapacity(minCapacity); 74 } 75 //如果大于,说明容量足够 76 } 77 78 //这个是1.7之后新加入的,主要是为了内部确保集合容量,与ensureCapacity相似,但是一个是public可以供外部使用,一个是private供内部使用 79 private void ensureCapacityInternal(int minCapacity) { 80 if (elementData == EMPTY_ELEMENTDATA) { 81 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); 82 } 83 ensureExplicitCapacity(minCapacity); 84 } 85 86 private void ensureExplicitCapacity(int minCapacity) { 87 modCount++; 88 89 // 如果当前的实际容量小于需要的最小容量,则扩容 90 if (minCapacity - elementData.length > 0) 91 grow(minCapacity); 92 } 93 // 这里定义了一个最大的数组长度,为什么会减8个字节了,我查了一下, 94 // as the Array it self needs 8 bytes to stores the size 2,147,483,648 95 //暂且理解的意思是需要8个字节来存储数组的长度值,其实这个主要也是由虚拟机决定。 96 97 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 98 /* 99 这个是扩容的实现;这里要注意一下,每次的扩容其实是到之前的1.5倍; 100 oldCapacity + (oldCapacity >> 1) 实际上就是右移除2 结果是3/2oldCapacity 101 */ 102 private void grow(int minCapacity) { 103 // overflow-conscious code 104 int oldCapacity = elementData.length; 105 int newCapacity = oldCapacity + (oldCapacity >> 1); 106 if (newCapacity - minCapacity < 0) 107 newCapacity = minCapacity; 108 if (newCapacity - MAX_ARRAY_SIZE > 0) 109 newCapacity = hugeCapacity(minCapacity); 110 // minCapacity is usually close to size, so this is a win: 111 elementData = Arrays.copyOf(elementData, newCapacity); 112 } 113 //用来判断是否超出数组最大范围 114 private static int hugeCapacity(int minCapacity) { 115 if (minCapacity < 0) // overflow 116 throw new OutOfMemoryError(); 117 return (minCapacity > MAX_ARRAY_SIZE) ? 118 Integer.MAX_VALUE : 119 MAX_ARRAY_SIZE; 120 } 121 122 //返回ArrayList的实际大小 123 public int size() { 124 return size; 125 } 126 127 //判断ArrayList是否为空 128 public boolean isEmpty() { 129 return size == 0; 130 } 131 132 //判断是否包含某个元素 133 public boolean contains(Object o) { 134 return indexOf(o) >= 0; 135 } 136 137 //从头开始查找某个元素,返回元素的索引值,注意,我们从源码中可以看到,是可以查找空值的。。并且没有找到是返回-1 138 public int indexOf(Object o) { 139 if (o == null) { 140 for (int i = 0; i < size; i++) 141 if (elementData[i]==null) 142 return i; 143 } else { 144 for (int i = 0; i < size; i++) 145 if (o.equals(elementData[i])) 146 return i; 147 } 148 return -1; 149 } 150 151 //反向从最后开始查找,与上面相反 152 public int lastIndexOf(Object o) { 153 if (o == null) { 154 for (int i = size-1; i >= 0; i--) 155 if (elementData[i]==null) 156 return i; 157 } else { 158 for (int i = size-1; i >= 0; i--) 159 if (o.equals(elementData[i])) 160 return i; 161 } 162 return -1; 163 } 164 165 //执行克隆,注意这是一个浅克隆,并没有复制数组去创建一个新的,只是将一个新引用指向同一个对象而已。 166 public Object clone() { 167 try { 168 @SuppressWarnings("unchecked") 169 ArrayList<E> v = (ArrayList<E>) super.clone(); 170 v.elementData = Arrays.copyOf(elementData, size); 171 v.modCount = 0; 172 return v; 173 } catch (CloneNotSupportedException e) { 174 // this shouldn't happen, since we are Cloneable 175 throw new InternalError(); 176 } 177 } 178 179 //返回集合中元素以数组形式 180 public Object[] toArray() { 181 return Arrays.copyOf(elementData, size); 182 } 183 184 //以指定T类型数组形式返回 185 @SuppressWarnings("unchecked") 186 public <T> T[] toArray(T[] a) { 187 //如果数组a的大小<集合的大小,也就是元素的个数 188 if (a.length < size) 189 // 返回一个新的T类型的数组,将集合中的元素全部拷贝过去 190 return (T[]) Arrays.copyOf(elementData, size, a.getClass()); 191 //否则数组a的大小>=集合的大小,则直接将集合中的数组全部拷贝到数组a中去 192 System.arraycopy(elementData, 0, a, 0, size); 193 //注意:因为数组此时大小是大于集合中的元素的,拷贝之后会有剩余的空间,全部设置为null 194 if (a.length > size) 195 a[size] = null; 196 return a; 197 } 198 199 //返回指定下标的元素 200 @SuppressWarnings("unchecked") 201 E elementData(int index) { 202 return (E) elementData[index]; 203 } 204 205 //返回指定下标的元素 206 public E get(int index) { 207 rangeCheck(index);//这个方法主要是检查下标是否越界 208 209 return elementData(index); 210 } 211 212 //设置指定下标的值 213 public E set(int index, E element) { 214 rangeCheck(index);//这个方法主要是检查下标是否越界 215 //先找到指定位置值 216 E oldValue = elementData(index); 217 elementData[index] = element; 218 return oldValue; 219 } 220 221 //从尾部添加元素 222 public boolean add(E e) { 223 //先扩容 224 ensureCapacityInternal(size + 1); // Increments modCount!! 225 elementData[size++] = e; 226 return true; 227 } 228 229 //在指定的下标添加元素 230 public void add(int index, E element) { 231 rangeCheckForAdd(index);//是否越界 232 //扩容 233 ensureCapacityInternal(size + 1); // Increments modCount!! 234 //第一个elementData代表源数组,index代表从此下标开始截取,第二个elementData代表现在的目标数组,会将前面截取的数组从下标index + 1处开始覆盖 235 //例如数组{1,2,3,4,5} index=1 ,截取长度size - index为4,则第一个截取为{2,3,4,5},然后从index=2开始覆盖,得到{1,2,2,3,4,5,6}此时数组已经扩容了 236 //最后设置index=1处值即可,完成添加 237 System.arraycopy(elementData, index, elementData, index + 1, 238 size - index); 239 elementData[index] = element; 240 size++; 241 } 242 243 //删除指定位置的元素并返回元素的值 244 public E remove(int index) { 245 rangeCheck(index);//看下标是否越界 246 247 modCount++; 248 249 E oldValue = elementData(index);//保存删除的元素 250 251 int numMoved = size - index - 1;//代表在index下标之后的全部元素的数量 252 if (numMoved > 0)//如果index不是最后一个元素 253 //采用复制数组的方式将index覆盖删除 254 System.arraycopy(elementData, index+1, elementData, index, 255 numMoved); 256 elementData[--size] = null; //注意最后还要将最后一个元素设置为空,这是一个多余的重复元素 257 258 return oldValue; 259 } 260 261 //删除指定位置的元素,返回是否成功 262 public boolean remove(Object o) { 263 //这个比较清晰,注意内部将空的元素与非空元素分开处理的,不过都是从头到尾扫描 264 if (o == null) { 265 for (int index = 0; index < size; index++) 266 if (elementData[index] == null) { 267 fastRemove(index);//如果确认存在这个元素,调用的快速删除 268 return true; 269 } 270 } else { 271 for (int index = 0; index < size; index++) 272 if (o.equals(elementData[index])) { 273 fastRemove(index); 274 return true; 275 } 276 } 277 return false; 278 } 279 280 //已经确认了存在要删除的元素,就直接找到删除,与remove()方法内部一样 281 private void fastRemove(int index) { 282 modCount++; 283 int numMoved = size - index - 1; 284 if (numMoved > 0) 285 System.arraycopy(elementData, index+1, elementData, index, 286 numMoved); 287 elementData[--size] = null; // clear to let GC do its work 288 } 289 290 //清空集合内部所有的元素,遍历设置为空 291 public void clear() { 292 modCount++; 293 294 // clear to let GC do its work 295 for (int i = 0; i < size; i++) 296 elementData[i] = null; 297 298 size = 0; 299 } 300 301 //将Collection容器中的元素全部以迭代的方式添加到此列表的尾部 302 public boolean addAll(Collection<? extends E> c) { 303 Object[] a = c.toArray();//复制数组 304 int numNew = a.length;//长度 305 ensureCapacityInternal(size + numNew); // 扩容,准备添加到列表尾部 306 //取数组a,从0下标开始,长度为numNew,来覆盖数组elementData,下标从size开始,即从最后开始尾部添加 307 System.arraycopy(a, 0, elementData, size, numNew); 308 size += numNew;//添加完后要相应长度增加 309 return numNew != 0;//如果参数中的容器元素为空,返回false,否则返回true 310 } 311 312 //从指定位置index处开始添加元素 313 public boolean addAll(int index, Collection<? extends E> c) { 314 //与rangeCheck方法功能相似,也是判断下标是否越界,些许的区别是允许边界判断允许等于长度即从尾部开始添加,当然必须大于0啦 315 rangeCheckForAdd(index); 316 317 Object[] a = c.toArray(); 318 int numNew = a.length; 319 ensureCapacityInternal(size + numNew); // 这三句与上面一样 320 321 /*我还是习惯用实例来分析,假设现在我们本来的列表为elementData={1,3,5,7,9} 322 参数index=1,a={2,4,6,8},则numMoved = size - index=size + numNew-index=8 注意这里已经扩容了,不然下面的复制操作会报 323 ArrayIndexOutOfBoundsException异常;即现在新的elementData={1,3,5,7,9,null,null,null,null} 324 开始逐步分析: 325 执行这句System.arraycopy(elementData, index, elementData, index + numNew,numMoved); 326 (1)elementData中从index(包括index)取numMoved长度的数组,即{3,5,7,9,null,null,null,null} 327 (2)elementData中从index + numNew = 5处(包括index + numNew)开始执行覆盖,即{1,3,5,7,9,3,5,7,9}后面的null舍弃. 328 执行System.arraycopy(a, 0, elementData, index, numNew); 329 (1)a数组中从0开始取numNew长度数组,即{2,4,6,8} 330 (2)elementData从index=1处(包括index)开始执行覆盖,即{1,2,4,6,8,3,5,7,9} 331 全部过程执行完毕,实现了从index插入数组。 332 */ 333 int numMoved = size - index;//这是为了准备取index之后的元素 334 if (numMoved > 0) 335 System.arraycopy(elementData, index, elementData, index + numNew, 336 numMoved); 337 338 System.arraycopy(a, 0, elementData, index, numNew); 339 size += numNew; 340 return numNew != 0;//如果参数中的容器元素为空,返回false,否则返回true 341 } 342 343 //删除指定位置范围内的元素,从fromIndex(包括)到toIndex(不包括) 344 protected void removeRange(int fromIndex, int toIndex) { 345 modCount++; 346 int numMoved = size - toIndex; 347 //此处分析过程与上面一样 348 System.arraycopy(elementData, toIndex, elementData, fromIndex, 349 numMoved); 350 351 // clear to let GC do its work 352 int newSize = size - (toIndex-fromIndex); 353 for (int i = newSize; i < size; i++) { 354 elementData[i] = null;//从这里可以看出其实集合中的实际容量并不止这些,还有将后面的闲置的空间设置为空,便于GC去回收 355 } 356 size = newSize;//删除后要更新长度 357 } 358 359 //根据源码的注释说明,这个方法并不会检查index为负数的情况,但是它会在访问数组之前,直接抛出ArrayIndexOutOfBoundsException异常 360 private void rangeCheck(int index) { 361 if (index >= size) 362 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 363 } 364 365 //主要是给add and addAll两个方法判断下标是否越界使用 366 private void rangeCheckForAdd(int index) { 367 if (index > size || index < 0) 368 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 369 } 370 371 //主要用于抛出异常时定位详细信息 372 private String outOfBoundsMsg(int index) { 373 return "Index: "+index+", Size: "+size; 374 } 375 376 377 //删除指定Collection中包含的元素,即只要是Collection中含有的元素,在列表中进行删除操作,会得到一个新的列表 378 public boolean removeAll(Collection<?> c) { 379 return batchRemove(c, false); 380 } 381 382 //与上面的方法相反,仅仅保留Collection中含有的元素,相当于两个列表取交集 383 public boolean retainAll(Collection<?> c) { 384 return batchRemove(c, true); 385 } 386 387 //这个内部方法只分析false过程,true过程相似 388 private boolean batchRemove(Collection<?> c, boolean complement) { 389 final Object[] elementData = this.elementData;//获得列表中的数组 390 int r = 0, w = 0; 391 boolean modified = false; 392 try { 393 for (; r < size; r++)//遍历列表,如果参数complement传进来默认为fasle 394 if (c.contains(elementData[r]) == complement)//变量列表中的所有元素是否存在与c中 395 elementData[w++] = elementData[r];//如果不存在,则将不存在的元素存放在elementData中前列,也就是从头开始覆盖掉与c中重复的元素只保留不同的元素 396 //这个其实就是找出两个列表中的不同元素放在原始列表的前段,相当于去除了相同的元素; 397 //如果参数为true,则是找出两个列表中的相同元素放在原始列表的前段,相当于取出了交集元素; 398 } finally { 399 // Preserve behavioral compatibility with AbstractCollection, 400 // even if c.contains() throws. 401 if (r != size) { 402 //finally中的功能实际上是通过复制覆盖截取列表前段已经找出来的不同元素 403 System.arraycopy(elementData, r, 404 elementData, w, 405 size - r); 406 w += size - r; 407 } 408 if (w != size) { 409 // 主要是为了将列表后半段相同的元素置NULL,便于GC回收 410 for (int i = w; i < size; i++) 411 elementData[i] = null; 412 modCount += size - w; 413 size = w;//更新列表中的实际元素个数即长度 414 modified = true; 415 } 416 } 417 return modified; 418 } 419 // java.io.Serializable的写入函数 420 // 将ArrayList的“容量,所有的元素值”都写入到输出流中 421 private void writeObject(java.io.ObjectOutputStream s) 422 throws java.io.IOException{ 423 424 int expectedModCount = modCount;//记录标记 425 s.defaultWriteObject(); 426 //写入“数组的容量” 427 s.writeInt(size); 428 429 // 写入列表中的每一个元素 430 for (int i=0; i<size; i++) { 431 s.writeObject(elementData[i]); 432 } 433 //这个变量我理解的是防止在写入输出流的同时,又在进行列表的删除或添加操作,保证单线程安全问题; 434 if (modCount != expectedModCount) { 435 throw new ConcurrentModificationException(); 436 } 437 } 438 439 //与上面的对应,读取输出流 440 private void readObject(java.io.ObjectInputStream s) 441 throws java.io.IOException, ClassNotFoundException { 442 elementData = EMPTY_ELEMENTDATA;//默认为空 443 444 s.defaultReadObject(); 445 446 s.readInt(); // 从输入流中读取列表容量 447 448 if (size > 0) { 449 // 确保实际容量 450 ensureCapacityInternal(size); 451 452 Object[] a = elementData; 453 // 将输入流中的所有元素读取出来并赋值 454 for (int i=0; i<size; i++) { 455 a[i] = s.readObject(); 456 } 457 } 458 } 459 460 //迭代器 461 public ListIterator<E> listIterator(int index) { 462 if (index < 0 || index > size) 463 throw new IndexOutOfBoundsException("Index: "+index); 464 return new ListItr(index); 465 } 466 467 public ListIterator<E> listIterator() { 468 return new ListItr(0); 469 } 470 471 public Iterator<E> iterator() { 472 return new Itr(); 473 } 474 /*Itr内部类,实现了Iterator接口,主要是实现迭代器的功能,也就是设计模式适配器思想,用于迭代出列表中的全部元素,*/ 475 private class Itr implements Iterator<E> { 476 int cursor; // 默认的返回迭代的下一个元素索引 477 int lastRet = -1; // 默认的返回最后一个元素的索引,如果数组为空直接返回-1 478 int expectedModCount = modCount; 479 //是否还存在下一个元素,即是否迭代到列表尾部 480 public boolean hasNext() { 481 return cursor != size;//迭代到尾部返回true,否则返回false 482 } 483 484 //获取下一个元素值 485 @SuppressWarnings("unchecked") 486 public E next() { 487 checkForComodification();//检查线程安全,迭代同时列表是否改变 488 int i = cursor; 489 if (i >= size)//先判断是否超出列表容量 490 throw new NoSuchElementException(); 491 Object[] elementData = ArrayList.this.elementData;//获取列表元素数组 492 if (i >= elementData.length) 493 throw new ConcurrentModificationException(); 494 cursor = i + 1;//记住指向下一个元素索引,便于下次迭代 495 return (E) elementData[lastRet = i];//更新lastRet值 496 } 497 //从尾部开始删除 498 public void remove() { 499 if (lastRet < 0)//其实就是-1,则列表为空 500 throw new IllegalStateException(); 501 checkForComodification(); 502 503 try { 504 ArrayList.this.remove(lastRet);//从最后开始删除 505 cursor = lastRet; 506 lastRet = -1; 507 expectedModCount = modCount; 508 } catch (IndexOutOfBoundsException ex) { 509 throw new ConcurrentModificationException(); 510 } 511 } 512 513 final void checkForComodification() { 514 if (modCount != expectedModCount) 515 throw new ConcurrentModificationException(); 516 } 517 } 518 /*ListItr内部类,继承了Itr类,实现了迭代器功能,主要是继承了ListIterator接口 519 系列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。 520 ListIterator 没有当前元素;它的光标位置 始终位于调用 previous() 所返回的元素和调用 next() 所返回的元素之间。 521 长度为 n 的列表的迭代器有 n+1 个可能的指针位置 522 */ 523 private class ListItr extends Itr implements ListIterator<E> { 524 //带参数的构造函数 525 ListItr(int index) { 526 super(); 527 cursor = index; 528 } 529 /*如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。 530 换句话说,如果 previous 返回一个元素而不是抛出异常,则返回 true)。 531 其实就是确定当前迭代出的元素是否有前任元素,当迭代出的是第一个元素时, 532 */ 533 public boolean hasPrevious() { 534 return cursor != 0; 535 } 536 //返回下一个元素的索引,如果迭代到列表的尾部,则返回列表的大小 537 public int nextIndex() { 538 return cursor; 539 } 540 //返回当前迭代元素的 541 public int previousIndex() { 542 return cursor - 1; 543 } 544 545 @SuppressWarnings("unchecked") 546 public E previous() { 547 checkForComodification(); 548 int i = cursor - 1; 549 if (i < 0) 550 throw new NoSuchElementException(); 551 Object[] elementData = ArrayList.this.elementData; 552 if (i >= elementData.length) 553 throw new ConcurrentModificationException(); 554 cursor = i; 555 return (E) elementData[lastRet = i]; 556 } 557 558 public void set(E e) { 559 if (lastRet < 0) 560 throw new IllegalStateException(); 561 checkForComodification(); 562 563 try { 564 ArrayList.this.set(lastRet, e); 565 } catch (IndexOutOfBoundsException ex) { 566 throw new ConcurrentModificationException(); 567 } 568 } 569 570 public void add(E e) { 571 checkForComodification(); 572 573 try { 574 int i = cursor; 575 ArrayList.this.add(i, e); 576 cursor = i + 1; 577 lastRet = -1; 578 expectedModCount = modCount; 579 } catch (IndexOutOfBoundsException ex) { 580 throw new ConcurrentModificationException(); 581 } 582 } 583 } 584 585 //返回一个新的列表,范围是fromIndex到toIndex 586 public List<E> subList(int fromIndex, int toIndex) { 587 subListRangeCheck(fromIndex, toIndex, size); 588 //直接用构造函数构建 589 return new SubList(this, 0, fromIndex, toIndex); 590 } 591 //检查下标的范围是否越界 592 static void subListRangeCheck(int fromIndex, int toIndex, int size) { 593 if (fromIndex < 0) 594 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); 595 if (toIndex > size) 596 throw new IndexOutOfBoundsException("toIndex = " + toIndex); 597 if (fromIndex > toIndex) 598 throw new IllegalArgumentException("fromIndex(" + fromIndex + 599 ") > toIndex(" + toIndex + ")"); 600 } 601 /* 602 SubList内部类,继承了AbstractList抽象类,AbstractList实现了AbstractCollection,适配器设计模式; 603 实现了RandomAccess接口支持随机访问; 604 */ 605 private class SubList extends AbstractList<E> implements RandomAccess { 606 private final AbstractList<E> parent;//原始列表 607 private final int parentOffset;//原始列表的偏移量 608 private final int offset;//偏移量 609 int size; 610 //构造函数初始化 611 SubList(AbstractList<E> parent, 612 int offset, int fromIndex, int toIndex) { 613 this.parent = parent; 614 this.parentOffset = fromIndex;//初始化为要截取列表的开始下标 615 this.offset = offset + fromIndex;//初始化为要截取列表的开始下标,这里假定从原始列表的头开始算,初始偏移量为0 616 this.size = toIndex - fromIndex;//截取的长度 617 this.modCount = ArrayList.this.modCount; 618 } 619 //设置指定下标的值 620 public E set(int index, E e) { 621 rangeCheck(index); 622 checkForComodification(); 623 E oldValue = ArrayList.this.elementData(offset + index); 624 ArrayList.this.elementData[offset + index] = e;//注意这里还要加上偏移量,因为可能有时候并不是从第一个元素开始; 625 return oldValue;//并返回被覆盖的元素 626 } 627 //获取指定下标的值,并返回值 628 public E get(int index) { 629 rangeCheck(index); 630 checkForComodification(); 631 return ArrayList.this.elementData(offset + index); 632 } 633 //获取当前列表长度 634 public int size() { 635 checkForComodification(); 636 return this.size; 637 } 638 //在指定位置添加元素 639 public void add(int index, E e) { 640 rangeCheckForAdd(index); 641 checkForComodification(); 642 parent.add(parentOffset + index, e); 643 this.modCount = parent.modCount; 644 this.size++; 645 } 646 //删除指定下标的元素 647 public E remove(int index) { 648 rangeCheck(index); 649 checkForComodification(); 650 E result = parent.remove(parentOffset + index); 651 this.modCount = parent.modCount; 652 this.size--; 653 return result; 654 } 655 //删除指定范围内的元素 656 protected void removeRange(int fromIndex, int toIndex) { 657 checkForComodification(); 658 //调用的是AbstractList中的removeRange方法,采用迭代逐一删除元素 659 parent.removeRange(parentOffset + fromIndex, 660 parentOffset + toIndex); 661 this.modCount = parent.modCount; 662 this.size -= toIndex - fromIndex; 663 } 664 //将c中的元素全部添加到当前列表的尾部 665 public boolean addAll(Collection<? extends E> c) { 666 return addAll(this.size, c); 667 } 668 //将c中的元素全部添加到当前列表的指定index位置 669 public boolean addAll(int index, Collection<? extends E> c) { 670 rangeCheckForAdd(index); 671 int cSize = c.size(); 672 if (cSize==0) 673 return false;//为null直接返回 674 675 checkForComodification(); 676 parent.addAll(parentOffset + index, c); 677 this.modCount = parent.modCount; 678 this.size += cSize; 679 return true; 680 } 681 682 public Iterator<E> iterator() { 683 return listIterator(); 684 } 685 686 public ListIterator<E> listIterator(final int index) { 687 checkForComodification(); 688 rangeCheckForAdd(index); 689 final int offset = this.offset; 690 691 return new ListIterator<E>() { 692 int cursor = index; 693 int lastRet = -1; 694 int expectedModCount = ArrayList.this.modCount; 695 696 public boolean hasNext() { 697 return cursor != SubList.this.size; 698 } 699 700 @SuppressWarnings("unchecked") 701 public E next() { 702 checkForComodification(); 703 int i = cursor; 704 if (i >= SubList.this.size) 705 throw new NoSuchElementException(); 706 Object[] elementData = ArrayList.this.elementData; 707 if (offset + i >= elementData.length) 708 throw new ConcurrentModificationException(); 709 cursor = i + 1; 710 return (E) elementData[offset + (lastRet = i)]; 711 } 712 713 public boolean hasPrevious() { 714 return cursor != 0; 715 } 716 717 @SuppressWarnings("unchecked") 718 public E previous() { 719 checkForComodification(); 720 int i = cursor - 1; 721 if (i < 0) 722 throw new NoSuchElementException(); 723 Object[] elementData = ArrayList.this.elementData; 724 if (offset + i >= elementData.length) 725 throw new ConcurrentModificationException(); 726 cursor = i; 727 return (E) elementData[offset + (lastRet = i)]; 728 } 729 730 public int nextIndex() { 731 return cursor; 732 } 733 734 public int previousIndex() { 735 return cursor - 1; 736 } 737 738 public void remove() { 739 if (lastRet < 0) 740 throw new IllegalStateException(); 741 checkForComodification(); 742 743 try { 744 SubList.this.remove(lastRet); 745 cursor = lastRet; 746 lastRet = -1; 747 expectedModCount = ArrayList.this.modCount; 748 } catch (IndexOutOfBoundsException ex) { 749 throw new ConcurrentModificationException(); 750 } 751 } 752 753 public void set(E e) { 754 if (lastRet < 0) 755 throw new IllegalStateException(); 756 checkForComodification(); 757 758 try { 759 ArrayList.this.set(offset + lastRet, e); 760 } catch (IndexOutOfBoundsException ex) { 761 throw new ConcurrentModificationException(); 762 } 763 } 764 765 public void add(E e) { 766 checkForComodification(); 767 768 try { 769 int i = cursor; 770 SubList.this.add(i, e); 771 cursor = i + 1; 772 lastRet = -1; 773 expectedModCount = ArrayList.this.modCount; 774 } catch (IndexOutOfBoundsException ex) { 775 throw new ConcurrentModificationException(); 776 } 777 } 778 779 final void checkForComodification() { 780 if (expectedModCount != ArrayList.this.modCount) 781 throw new ConcurrentModificationException(); 782 } 783 }; 784 } 785 //返回原始列表范围的部分列表,从fromIndex(包括)开始,到toIndex(不包括) 786 public List<E> subList(int fromIndex, int toIndex) { 787 subListRangeCheck(fromIndex, toIndex, size); 788 return new SubList(this, offset, fromIndex, toIndex); 789 } 790 791 private void rangeCheck(int index) { 792 if (index < 0 || index >= this.size) 793 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 794 } 795 796 private void rangeCheckForAdd(int index) { 797 if (index < 0 || index > this.size) 798 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 799 } 800 801 private String outOfBoundsMsg(int index) { 802 return "Index: "+index+", Size: "+this.size; 803 } 804 805 private void checkForComodification() { 806 if (ArrayList.this.modCount != this.modCount) 807 throw new ConcurrentModificationException(); 808 } 809 } 810 }
还是总结一下
(1)其实源码里面还是有一些代码不太懂,例如modCount变量,只知道是与线程安全相关,ArrayList是不安全的,可能与这个相关,在多线程下不建议使用;以后可以再回头看看仔细琢磨一些实现细节。
(2)ArrayList的实现中大量调用了 Arrays.copyof()和System.arraycopy()方法,这两个方法之前内部实现了解的不多,后来看源码仔细琢磨了一下,在上面有对它们的详细注解分析过程,相信看过之后应该会比较清晰,按我的理解实际上就是自我复制与自我覆盖。
(3)ArrayList是基于数组的存储结构,所以支持随机读取,是通过下标索引查找指定元素,但是在插入删除的时候效率很低,因为要大量的复制移动数组元素。
(4)ArrayList支持迭代,内部数组存储允许重复元素,特别也允许null的元素,也支持null元素的查找,从上面的源码分析看出内部是将null元素与普通元素分成两种情况分别遍历查找。