浅克隆
Address.java
public class Address implements Cloneable{
private String address;
public Address(String address) {
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address +
'}';
}
}
Customer.java
public class Customer implements Cloneable{
private int age;
private String name;
private Address address;
// 实现克隆方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Customer{" +
"age=" + age +
", name='" + name + '\'' +
", address=" + address.toString() +
'}';
}
}
下面是测试方法以及结果
public class CloneMain {
public static void main(String[] args) {
Address address = new Address("狗窝");
Customer customer = new Customer();
customer.setAge(18);
customer.setName("二狗子");
customer.setAddress(address);
customer.toString();
try {
Customer clone = (Customer) customer.clone();
clone.setAge(14);
clone.setName("三驴子");
clone.getAddress().setAddress("驴棚");
System.out.println("********************customer********************");
System.out.println(customer.toString());
System.out.println("********************clone********************");
System.out.println(clone.toString());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
********************customer********************
Customer{age=18, name='二狗子', address=Address{address='驴棚}}
********************clone********************
Customer{age=14, name='三驴子', address=Address{address='驴棚}}
BUILD SUCCESSFUL in 692ms
很明显,clone后基本数据类型没有收到干扰,引用类型的把之前的数据都改了,二狗子失去了狗窝!这是浅复制的弊端,引用类型指向的是同一个对象!
深复制
只需重写Customer.java的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Customer customer = (Customer) super.clone();
customer.setAddress((Address) address.clone());
return customer;
}
执行结果
> Task :proxy:CloneMain.main()
********************customer********************
Customer{age=18, name='二狗子', address=Address{address='狗窝}}
********************clone********************
Customer{age=14, name='三驴子', address=Address{address='驴棚}}
BUILD SUCCESSFUL in 448ms
结果很明显,二狗子和三驴子不是同一个窝了!clone方法把对象也在堆中clone了一份,引用各指向各的对象!
总结
Java的数据类型分为基本数据类型和引用数据类型,这两种类型传递时会有值传递和引用传递两种!
基本数据类型的变量指向虚拟机栈,引用类型的变量指向堆。
浅克隆不能实现内存上的克隆,即不能实现真正意义上的对象“复制”,克隆后的内部引用与之前对象的引用指向同一块内存。深克隆要求类中所有的类都要实现Cloneable接口并重写clone方法!