JDK1.8 源码阅读(2)——List<T>重点标注

190 阅读4分钟

List接口的中文文档 具体详细信息阅读文档就可以了,下面只是记录一些重要的内容:

  1. 如果列表长度超过Integer.MAX_VALUE的话,那么返回Integer.MAX_VALUE
  2. 如果该列表不允许包含null元素,如果onull,则抛出NullPointerException
  3. toArray方法返回数组的时候,链表内部不持有对该链表的引用。
  4. toArray中:
  • 如果传入的数组运行时类型不是list对应的父类时,则抛出ArrayStoreException
  • 如果传入的数组运行时满足要求,但是数组的长度大于链表中元素的个数时,超出部分全部设置为null
  • 如果指定的数组是null时,则抛出NullPointerException
  • 如果指定的数组长度小于列表长度时,返回一个新的长度为列表长度,内容为列表中所有元素的数组,传递进来的数组则保持原样。

另外要注意的是,两个toArray方法传递出来的数组,虽然数组的引用列表不持有,但是数组里面的元素与列表中的元素是一个引用,因此更改数组某个元素的某个属性会更改列表对应元素的属性,但是如果更改数组某个元素的引用,比如a[0] = new MyObj()则不会影响列表内部数据,毕竟这个修改的是数组的‘属性’,跟列表无关

  1. add中,如果列表拒绝null元素,则在添加null元素的时候,抛出NullPointerException
  2. remove方法移除的是最低索引的元素。
  3. addAll方法在操作进行中,指定集合发生了修改,则次操作行为未定义(比如a.addAll(a),即集合自己添加自己的时候,添加的时候,作为参数的a也同时发生了改变,这时候结果是未知的,当然还有很多种情况)

在AbstractList(ArrayList的父类)中,undefined的具体表现形式是抛出一个ConcurrentModificationException。

8. 列表只删除removeAll方法作为参数的列表同样包含的元素,也即删除两个列表的交集元素,不在交集的元素不删除。如果列表没有作出任何改变(没有删除),则返回false,如果发生改变(删除)返回true
9. retainAll方法删除不包含在作为参数传入的列表中的元素。作出改变返回true,没有改变返回false
10. replaceAll
11. equals方法在两者均为列表,且在相同位置上包含相同元素时返回true,否则返回false
12. 列表hashCode计算方式如图所示,为什么采用31*hashCode这个式子,查了一下资料,就是hashCode要尽量保证不重复,所以经常使用素数,而31=(2<<4)-1很容易通过移位操作来获取,因此使用这个式子。
13. add(index,obj)添加元素,指定位置以及后面的元素全部后移一位(索引+1),指定位置变为指定的元素(obj)。
14. remove(index)移除元素后,指定位置以及后面的元素全部前移移位(索引-1)。
15. indexOf(obj)找寻指定元素的索引位置:

  • 若该列表允许存在null元素:若obj==null,则查找null元素下标,若没有返回-1,若有,返回null元素下标。
  • 若该列表不允许存在null元素:若obj==null,则抛出NullPointerException
  • obj!=null,返回obj对应的最低下标,若不存在该元素,则返回-1
  1. lastIndexOf(obj)indexOf(obj)一样,只不过若obj在列表中存在,则返回对应的最高下标,即最后出现的索引。
  2. listIterator
  3. subList返回的子列表对其做任何非结构性更改(即更改一些数据)都会反应到原本的列表,如果对子列表做结构性更改(比如更改长度),那么也会反映到原本的列表中(即原本列表的长度也会更改),如果对原本的列表进行结构性更改,如果影响到子列表(比如parentList.removeAll(childList)),那么对子列表的操作是未定义的(即此时childList.foreach(li->{System.out.println(li)})会报ConcurrentModificationException)。
  4. spliterator,这个方法在后面的函数式编程里面会详细说。