源码阅读笔记
所有集合类,在 for 循环进行删除时,如果直接使用集合类的 remove 方法进行删除,都会快速失败,报 ConcurrentModificationException 的错误,所以在任意循环删除的场景下,都建议使用迭代器进行删除;
我们把数组转化成集合时,常使用 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 的原因。
- 集合 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