源码阅读笔记

编程

  1. 所有集合类,在 for 循环进行删除时,如果直接使用集合类的 remove 方法进行删除,都会快速失败,报 ConcurrentModificationException 的错误,所以在任意循环删除的场景下,都建议使用迭代器进行删除;

  2. 我们把数组转化成集合时,常使用 Arrays.asList(array),这个方法有两个坑,代码演示坑为:

publicvoidtestArrayToList(){

Integer[] array =newInteger[]{1,2,3,4,5,6};

List<Integer> list = Arrays.asList(array);

// 坑1:修改数组的值,会直接影响原 list

log.info("数组被修改之前,集合第一个元素为:{}",list.get(0));

array[0]=10;

log.info("数组被修改之前,集合第一个元素为:{}",list.get(0));

// 坑2:使用 add、remove 等操作 list 的方法时,

// 会报 UnsupportedOperationException 异常

list.add(7);

}

1:数组被修改后,会直接影响到新 List 的值。

2:不能对新 List 进行 add、remove 等操作,否则运行时会报 UnsupportedOperationException 错误。

我们来看下 Arrays.asList 的源码实现,就能知道问题所在了,源码如下图:

从上图中,我们可以发现,Arrays.asList 方法返回的 List 并不是 java.util.ArrayList,而是自己内部的一个静态类,该静态类直接持有数组的引用,并且没有实现 add、remove 等方法,这些就是坑 1 和 2 的原因。

  1. 集合 List 转化成数组,我们通常使用 toArray 这个方法,这个方法很危险,稍微不注意,就踩进大坑,我们示例代码如下:

publicvoidtestListToArray(){

List<Integer> list =newArrayList<Integer>(){{

add(1);

add(2);

add(3);

add(4);

}};

// 下面这行被注释的代码这么写是无法转化成数组的,无参 toArray 返回的是 Object[],

// 无法向下转化成 List<Integer>,编译都无法通过

// List<Integer> list2 = list.toArray();

// 演示有参 toArray 方法,数组大小不够时,得到数组为 null 情况

Integer[] array0 =newInteger[2];

list.toArray(array0);

log.info("toArray 数组大小不够,array0 数组[0] 值是{},数组[1] 值是{},",array0[0],array0[1]);

// 演示数组初始化大小正好,正好转化成数组

Integer[] array1 =newInteger[list.size()];

list.toArray(array1);

log.info("toArray 数组大小正好,array1 数组[3] 值是{}",array1[3]);

// 演示数组初始化大小大于实际所需大小,也可以转化成数组

Integer[] array2 =newInteger[list.size()+2];

list.toArray(array2);

log.info("toArray 数组大小多了,array2 数组[3] 值是{},数组[4] 值是{}",array2[3],array2[4]);

}

19:33:07.687[main] INFO demo.one.ArrayListDemo - toArray 数组大小不够,array0 数组[0] 值是null,数组[1] 值是null,

19:33:07.697[main] INFO demo.one.ArrayListDemo - toArray 数组大小正好,array1 数组[3] 值是4

19:33:07.697[main] INFO demo.one.ArrayListDemo - toArray 数组大小多了,array2 数组[3] 值是4,数组[4] 值是null

toArray 的无参方法,无法强转成具体类型,这个编译的时候,就会有提醒,我们一般都会去使用带有参数的 toArray 方法,这时就有一个坑,如果参数数组的大小不够,这时候返回的数组值竟然是空,上述代码中的 array0 的返回值就体现了这点,但我们去看 toArray 源码,发现源码中返回的是 4 个大小值的数据,返回的并不是空,源码如下:

// List 转化成数组

public<T> T[]toArray(T[] a){

// 如果数组长度不够,按照 List 的大小进行拷贝,return 的时候返回的都是正确的数组

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);

// 数组长度大于 List 大小的,赋值为 null

if(a.length > size)

a[size]= null;

return a;

}

从源码中,我们丝毫看不出为什么 array0 的元素值为什么是 null,最后我们去看方法的注释,发现是这样子描述的:

If the list fits in the specified array, it is returned therein.  Otherwise, a newarray is

allocated with the runtime type of the specified array and the size of this list。

翻译过来的意思就是说:如果返回的数组大小和申明的数组大小一致,那么就会正常返回,否则,一个新数组就会被分配返回。

所以我们在使用有参 toArray 方法时,申明的数组大小一定要大于等于 List 的大小,如果小于的话,你会得到一个空数组。

以上是 源码阅读笔记 的全部内容, 来源链接: utcz.com/z/513390.html

回到顶部