关于Java中深拷贝与浅拷贝问题
文章目录
前言
在详细说明深拷贝与浅拷贝之前,我先给出一些相关代码,如下:
*********类Person***********
class Person implements Cloneable{
private String name; //姓名
private Integer age; //年龄
private Address address; //住址
//注意!!!setter/getter方法和无参、有参构造方法省略...
@Override
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
*********类Address***********
class Address {
private String location; //位置
//注意!!!setter/getter方法和无参、有参构造方法省略...
}
一、浅拷贝
浅拷贝会在堆上创建一个新的对象,不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。
代码:
public class ShallowAndDeepCopy {
public static void main(String[] args) {
Person person = new Person("yy", Integer.valueOf(20), new Address("某地"));
Person shallowCopy = person.clone();
System.out.println(person == shallowCopy); //false
System.out.println(person.getAddress() == shallowCopy.getAddress()); //ture
}
}
运行结果:
二、深拷贝
深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。
代码修改如下:
*********类Person的clone()***********
@Override
public Person clone() {
try {
Person person = (Person) super.clone();
person.setAddress(person.getAddress().clone());
return person;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
*********类Address的clone()***********
// class Address implements Cloneable
@Override
public Address clone() {
try {
return (Address) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
运行结果:
总结
扩展问题?
1. 为什么在类ShallowAndDeepCopy的main方法中创建Person类的实例person并调用clone() 的时候,Person类一定要实现Cloneable接口?
如果 Person 类不实现 Cloneable 接口,调用 clone 方法时会导致编译错误。因为如果不对重写的clone() 进行逻辑修改的话,本质上调用的时Object类中的clone(),而该方法是protected修饰的。
protected修饰符修饰的方法只能在本类、本包以及子类中使用,而在类ShallowAndDeepCopy中使用会报编译错误。也即是说,protected修饰的成员可以被子类(不同包的子类或同包的子类)访问是指父类的protected成员被子类继承,子类可以直接使用;不是在子类方法中创建父类对象,然后通过父类对象调用protected权限的方法。
2. Cloneable 接口
Cloneable 接口是 Java 中的一个标记接口(marker interface),它在设计上并没有包含任何方法。其主要作用是向类的使用者表示该类是可克隆的,即可以使用 Object 类的 clone 方法创建该类对象的副本。
Object 类中的 clone 方法声明了抛出 CloneNotSupportedException 异常。如果一个类希望使用 Object 类的 clone 方法而不抛出异常,那么该类必须实现 Cloneable 接口。否则,Object 类的 clone 方法在调用时可能会抛出异常。