深浅拷贝
1 认识浅拷贝
什么是浅拷贝?
我们一起来看一段代码了解一下
public class Blog {
public static void main(String[] args) {
String s1 = new String("我是原件");//一般来说不建议使用new的方法创造String的对象,这样会导致常量池中的String浪费,并且堆中占用内存
String s2 = s1;
System.out.println(s2);
}
}
/*
我是原件
*/
其实浅拷贝就是我们平时用的最多,也是最简单的,我们也把它叫做对象拷贝,我们只需要让副本的引用指向原件的对象,这样也就实现了两个地址相同,指向同一个对象,因此两个引用没有区别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IzXJDthU-1652285831913)(C:\Users\小艺\AppData\Roaming\Typora\typora-user-images\image-20220414133839999.png)]
这样的话会有什么不方便的地方呢?
我们修改其中“一个”对象的值的时候,会导致另一个对象也出现相应的修改
public class Blog {
public static void main(String[] args) {
Dog dog = new Dog();
Dog dog1 = dog;
System.out.println(dog1.getMood());
dog.setMood("心情不好");
System.out.println(dog1.getMood());
}
}
/*
心情好
心情不好
*/
我们可以看到,先创建一个Dog对象,引用dog指向它,并且默认设置为心情好
然后dog1引用指向引用dog,我们之后修改dog对象的属性,dog1也会随之改变
2 认识深拷贝
只复制 引用数据类型中的
数值
而不是复制地址
,称为深拷贝
其中需要用到clone()方法,该方法来自于Object类,因此所有类中都含有此方法
public class Blog {
public static void main(String[] args) throws CloneNotSupportedException {
Dog dog = new Dog();
Dog dog1 = (Dog) dog.clone();
System.out.println(dog1.getMood());
dog.setMood("心情不好");
System.out.println(dog1.getMood());
}
}
/*
心情好
心情好
*/
深拷贝又叫做对象拷贝,这样的操作,我们只是获得对象的各个字段的值,达到一种克隆的效果,这样我们改变其中一个对象的值不会影响另一个对象的值,这就叫做深拷贝,两个对象的值也是不同的。
深浅拷贝都是对象拷贝。
3 总结
我们在重写clone方法时,需要实现Cloneable
接口
例如
public class House implements Cloneable{
Person p;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
下面这一段代码
public class House implements Cloneable{
Person p;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Main {
public static void main(String[] args) {
House house = new House();
house.p=new Person();
System.out.println("house"+house+" "+"person:"+house.p);
House house1 = null;
try{
house1 = (House) house.clone();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("house"+house1+" "+"person:"+house1.p);
}
}
/*
运行结果
housecom.fq.clone.House@14ae5a5 person:com.fq.clone.Person@7f31245a
housecom.fq.clone.House@6d6f6e28 person:com.fq.clone.Person@7f31245a
*/
可以看到House对象是被重新拷贝了一份,但是其中的Person对象却还是原来的值,这说明clone方法默认是浅拷贝
的
我们可以这样解决这个问题
public class House implements Cloneable{
Person p;
@Override
protected Object clone() throws CloneNotSupportedException {
House house = null;
try {
house = (House) super.clone();
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
house.p = (Person) this.p.clone();
return house;
}
}
public class Person implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Main {
public static void main(String[] args) {
House house = new House();
house.p=new Person();
System.out.println("house"+house+" "+"person:"+house.p);
House house1 = null;
try{
house1 = (House) house.clone();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("house"+house1+" "+"person:"+house1.p);
}
}
/*
运行结果
housecom.fq.clone.House@14ae5a5 person:com.fq.clone.Person@7f31245a
housecom.fq.clone.House@6d6f6e28 person:com.fq.clone.Person@135fbaa4
*/
当一个对象是引用数据类型,并且他的成员属性中也有引用数据类型,这时候我们让所有的引用数据类型都实现Cloneable接口,并且重写其中的clone方法。