今天水群的时候看到群友分享的某厂面试关于深/浅克隆的一个问题,比较基础常见,整理出来跟各位大佬分享一波。
先说结论
- 浅克隆:浅克隆会在堆上创建一个新的对象,
- 如果属性是基本类型,克隆的就是基本类型的值;
- 如果属性是引用类型,克隆会直接复制内部对象的引用地址,也就是说克隆对象和原对象共用同一个内部对象(对象地址相同)。
- 深克隆 :深克隆会完全复制整个对象,包括这个对象所包含的内部对象。
浅克隆
浅克隆的示例很简单,我们这里实现了 Cloneable 接口,并重写了 clone() 方法。而 clone() 则是直接调用父类 Object 的 clone() 方法。
public class CloneDemo6 {
public static void main(String[] args) throws CloneNotSupportedException {
People p1 = new People(1, "张三", new Address("上海"));
People p2 = p1.clone();
System.out.println("a1 == a2:"+(p1.getAddress() == p2.getAddress()));
System.out.println("p1:"+p1 + ",hashcode:" + p1.hashCode());
System.out.println("p2:"+p2 + ",hashcode:" + p2.hashCode());
System.out.println("a1:"+p1.getAddress() + ",hashcode:" + p1.getAddress().hashCode());
System.out.println("a2:"+p2.getAddress() + ",hashcode:" + p2.getAddress().hashCode());
p1.setId(2);
p1.setName("李四");
System.out.println("改变原对象p1的基本类型与引用类型后,输出结果:");
p1.getAddress().setCity("北京");
System.out.println("a1 == a2:"+(p1.getAddress() == p2.getAddress()));
System.out.println("p1:"+p1 + ",hashcode:" + p1.hashCode());
System.out.println("p2:"+p2 + ",hashcode:" + p2.hashCode());
System.out.println("a1:"+p1.getAddress() + ",hashcode:" + p1.getAddress().hashCode());
System.out.println("a2:"+p2.getAddress() + ",hashcode:" + p2.getAddress().hashCode());
}
@Data
static class People implements Cloneable {
private Integer id;
private String name;
private Address address;
public People(Integer id, String name, Address address) {
this.id = id;
this.name = name;
this.address = address;
}
@Override
public People clone() throws CloneNotSupportedException {
People people = (People) super.clone();
return people;
}
}
@Data
static class Address implements Cloneable {
private String city;
public Address(String city) {
this.city = city;
}
@Override
public Address clone() throws CloneNotSupportedException {
return (Address) super.clone();
}
}
输出结果: 结论:
-
p1.getAddress() 和 p2.getAddress() 两个对象相等; -
更改 p1 对象中基本类型变量的值,不会影响p2 中基本变量的值; 总结:说明基础数据类型是值传递的,直接将属性值赋值给新的对象。修改其中一个对象的基础类型变量,不会影响另外一个对象中的基本类型变量。 -
更改 p1 对象里的引用类型 address 对象 的值,p2 对象中的 address 对象的也会被更改; 总结:说明 p1 和 p2 共用了 address 对象; -
关于 String 类型值改变不影响另一个对象的原因; 总结:String 是被 final 修饰的类 ,所以改变 String 修饰的变量,其实是创建了一个新的 String 对象,不会影响原对象;
深克隆
深克隆这里简单对 Person 类的 clone() 方法进行修改,克隆时把 Person 对象内部的 Address 对象一起克隆。
@Override
public People clone() throws CloneNotSupportedException {
People people = (People) super.clone();
people.setAddress(people.getAddress().clone());
return people;
}
输出结果: 从输出结构就可以看出,虽然 p1 与 p2 包含的 Address 对象已经是不同的了。
结论:
p1.getAddress() 和 p2.getAddress() 两个对象不相等;- 更改
p1 对象里的引用类型 address 对象 的值,p2 对象中的 address 对象的不会被更改; 总结:说明深克隆克隆了原对象所有属性,并给克隆对象的内部属性指向的动态分配的内存;
感 谢
各 位
大 佬
的 阅
读,随
手 点
赞,日
薪 过
万~!
!!
|