使用Collections.copy(List dest, List src)方法时的注意点
List src = new ArrayList();
list.add(1234);
list.add(123);
list.add(0);
list.add(4793);
list.add(-43);
List dest = new ArrayList();
Collections.copy(dest,src);
/*
这个时候会出现一个角标越界异常(IndexOutOfBoundException)
*/
System.out.println(dest);
那么上面为什么会出现这个异常?(这里我们就是用jdk8.0来作讲解,因为现在大部分都是使用的jdk8.0)
- 我们在创建一个ArrayList对象的时候底层开始是创建了一个长度为0的空数组,那么这个时候我们创建的这个新的集合底层是一个空数组,这个时候我们直接使用这个集合来接收来自src集合中的五个元素,这个时候肯定就会出现角标越界异常,那么当我们使用一次add()方法之后底层这个时候就会创建一个长度为10的数组,这个时候我们使用这个方法会不会出现异常?
- 如果我们去测试会发现还是会出现异常,这个时候我们底层创建的数组的长度为10,但是这个时候我们的集合的真正长度只有1,因为我们只使用了一次add()方法 ---- 这里我们必须要知道ArrayList集合中的底层数组的长度是elementDate.length(这个elementDate就是ArrayList集合底层的数组名),而集合长度为ArrayList中的size属性的值,但是这个size属性是私有的,对外不暴露,这个时候我们可以使用ArrayList类中的提供的size()方法去得到这个属性的大小,这个size就是我们集合中存储的元素的数目
- 而我们知道LIst集合中存储的元素是有序的,我们的List集合以ArrayList为例,我们的ArrayList集合是始终相连的,不能出现跳过一个元素添加到下一个元素位置上,那么怎样可以防止我们添加元素时跳过一个元素添加?
- 这个时候就是通过一个异常来限制(也就是通过一个条件来限制),那么这个限制条件是什么呐?
- 就是我们每次添加元素的时候就只能添加到集合中元素数目个数对应的索引位置处,举个例子: 就是如果我们这个集合中如果这时候没有元素,那么这个时候也就是元素为0,这个时候我们只能添加元素到索引为0的位置处,这个时候如果我们添加元素到索引为1的位置处,这个时候我就会给我们抛出一个角标越界异常(IndexOutOfBoundException)
- 这个时候如果我们去看copy()方法的源码我们就会发现,在copy()方法的底层中我们是通过set()方法在dest集合底层数组上的前面5个位置(这个例题中list.size()方法的返回值是5),这个时候如果我们的这个底层数组中的size小于4,这个时候我们添加到,假如就说这个dest的size为3,这个时候如果我们在设置索引为3的位置处的元素的时候这个时候就会出现一个角标越界异常
- 而我们知道LIst集合中存储的元素是有序的,我们的List集合以ArrayList为例,我们的ArrayList集合是始终相连的,不能出现跳过一个元素添加到下一个元素位置上,那么怎样可以防止我们添加元素时跳过一个元素添加?
- 如果我们去测试会发现还是会出现异常,这个时候我们底层创建的数组的长度为10,但是这个时候我们的集合的真正长度只有1,因为我们只使用了一次add()方法 ---- 这里我们必须要知道ArrayList集合中的底层数组的长度是elementDate.length(这个elementDate就是ArrayList集合底层的数组名),而集合长度为ArrayList中的size属性的值,但是这个size属性是私有的,对外不暴露,这个时候我们可以使用ArrayList类中的提供的size()方法去得到这个属性的大小,这个size就是我们集合中存储的元素的数目
那么我们要如何避免我们在使用Collections类中的copy()方法时出现这个问题?
-
我们这里提供了一种通用的方式:
List src = new ArrayList(); list.add(1234); list.add(123); list.add(0); list.add(4793); list.add(-43); /* 通过这种方式我们就可以快速的得到一个集合长度为5的集合(注意:这里是集合长度为5,而不是底层数组长度为5), 这个集合中的五个元素都为null */ List dest = Arrays.asList(new Object[5]); Collections.copy(dest,src); System.out.println(dest);
重点区分:
- 集合长度和集合底层数组长度
- 集合长度就是集合中的size属性的值,也就是集合中实际存储的元素数目
- 集合底层数组长度就是集合底层的数组elementDate的长度,也就是elementDate.length
原因总结:
- 由于ArrayList集合中的元素必须一个一个相连,而为了ArrayList集合中的元素在底层elementDate数组中是相连的,就要设定我们在ArrayList集合对象中添加元素时添加的索引位置必须在这个ArrayList集合对象的长度之内
- 由于是数组复制,这个时候我们赋值得到的两个数组必须内容要一样,这个时候我们就不能低层就不能用add()方法来实现,因为如果我们使用add()方法来实现,虽然避免了出现角标越界异常,但是又有可能会出现我们的目标集合的长度和我们原数组有差异,达不到我们的目的