之前对浅克隆、深克隆有一些了解,知道浅克隆意味着这对“双胞胎”持有的对象是同一个,其中一个如果改了持有对象的内容,另一个也会一起被改变。
在刷leetcode的时候,用到了ArrayList的复制,简单的用到了ArrayList.clone()方法进行复制,当时就有疑虑,会不会在改一个list的时候,另一个list的值也被改掉。所以自己做了一些测试
下面是代码
public static void main(String [] args){
Dog dog1 = new Dog("happy",5);
Dog dog2 = new Dog("xiaoming",2);
Dog dog3 = new Dog("wangcai",3);
Dog dog4 = new Dog("alibr",5);
ArrayList<Dog> list = new ArrayList<>();
list.add(dog1);
list.add(dog2);
list.add(dog3);
ArrayList<Dog> list2 = (ArrayList<Dog>) list.clone();
list.get(1).setName("huanghuang");
list.set(0,dog4);
//Collections.reverse(list2);
for (int i = 0;i<3;i++){
System.out.println(list.get(i).getName());
System.out.println("list2 "+list2.get(i).getName());
}
}
Dog类
class Dog{
String name;
int age;
public Dog(String name,int age){
this.name = name;
this.age = age;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
}
输出的内容是
alibr
list2 happy
huanghuang
list2 huanghuang
wangcai
list2 wangcai
可以看到
当list用get方法改变[0]号dog的名字时,list2的值也会跟着改变,但是如果用set方法就不会改变list2的值,带着疑惑,查看了一下源码
ArrayList的get方法
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
ArrayList的set方法
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
elementData方法
E elementData(int index) {
return (E) elementData[index];
}
看到这觉得get和set方法很相近,为什么结果会不同呢?后来思考了一下,得到答案。
ArrayList.clone()确实是浅克隆,但同时list和list2是两个不同的Arraylist。查看源码也可以看出,这两个list本质上都是elementData这个Object []数组。数组中存放的是对象引用。
大概画一个图
屏幕快照 2017-12-25 下午8.32.49.png
这样就一目了然了
当用get方法修改的时候,由于这两个list指向同一个Dog,所以两个的输出都会被修改
但是用set方法,就相当于将list的第一个数组对象指向了另外一个Dog
而此时list2的第一个数组对象仍然是指向第一个Dog
所以这时list2不会被改变。
网友评论