使用构造方法复制
java ArrayList构造方法中,存在这样一个构造函数
public ArrayList(Collection<? extends E> c)
利用一个集合,构造出一个新的ArrayList。这样就可以新建出一个和原来的集合相同的ArrayList。但是,需要注意的是,两个集合中的元素其实所指的对象是同一个,这种复制方法仅仅是复制了引用而已。
另外,addAll方法也是一样,添加的仅仅是引用,不会克隆对象。
@Test
public void listAdd() {
List<Result> list = new ArrayList<Result>();
list.add(new Result("1"));
list.add(new Result("2"));
list.add(new Result("3"));
List<Result> listCp = new ArrayList<Result>(list);
list.get(0).setMsg("ch");
for (Result result : listCp) {
System.out.println(result.getMsg());
}
//将会输出 ch,2,3
//
// List<Result> listCp = new ArrayList<Result>();
// listCp.addAll(list);
// list.get(0).setMsg("ch");
// for (Result result : listCp) {
// System.out.println(result.getMsg());
// }
//将会输出 ch,2,3
}
包装类型集合复制
包装类型由于自动装箱的缘故,复制后的集合与复制前的集合所指向的并非同一个内存对象,具体原因也不理解,先埋个坑。
@Test
public void longTest() {
List<Long> longList = new ArrayList<Long>();
longList.add(1L);
longList.add(2L);
longList.add(3L);
longList.add(4L);
List<Long> cpLong = new ArrayList<Long>(longList);
longList.set(0, 23L);
for (Long long1 : cpLong) {
System.out.println(long1);
}
//打印1,2,3,4
}
查看源码
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
//省略部分判断语句
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
该构造方法调用Arrays的copyOf方法
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
而copyOf最终会调用System.copyOf的方法进行数组的复制,该复制方法只是单纯的使用如 'a=b' 这种方法进行复制,因此该构造方法传入的集合只会引用的复制。
同样地,addAll方法源码也是调用的Arrays.copyOf()方法进行集合的增加。
深拷贝和浅拷贝
普通的集合复制只是将内存中栈的地址快拷贝一份,使得一个新的集合对象指向这个地址块,但是集合中的对象变量却是指向堆中的同一块区域。所以当拷贝的集合修改了集合对象内的数据,那么源集合对象也就随之改变了,这样的效果我们称之为Java集合对象的浅复制,即只是在栈中拷贝了,而堆中的数据并没有拷贝。我们上面所说的就是浅拷。
而深度复制则是同时在栈中和堆中的数据进行拷贝,这样,其拷贝的集合和被拷贝的集合已经没有任何关系了。
深拷贝的实现方法
我们可以通过继承cloneable接口,并实现clone()方法。然后通过调用该类的clone方法便可以得到一个深拷贝的实例复制。
public class Demo {
private int demoValue;
public void setDemoValue(int value){
this.demoValue = value;
}
public int getDemoValue(){
return this.demoValue;
}
public Demo(){
}
public Demo(int demoValue){
this.demoValue = demoValue;
}
继承接口后,clone实现的内容:
@Override
protected Demo clone() throws CloneNotSupportedException {
return (Demo)super.clone();
}
Collections.copy()
使用这个工具方法可以针对集合的复制简便的进行复制,而且是深拷贝,但需要注意目标集合的长度不能小于源集合,否则会抛出异常。
接口:
public static <T> void copy(List<? super T> dest, List<? extends T> src)
网友评论