浅克隆与深克隆
“万类之王”Object有11个方法,有两个protected的方法,其中一个为clone方法。Java中的克隆分为浅克隆(ShallowClone)和深克隆(DeepClone)。Object中定义的clone()方法如下:
protected native Object clone() throws CloneNotSupportedException;
可以看到,clone()是一个native方法,是非Java语言实现的代码,供Java程序调用的,因为Java程序是运行在JVM虚拟机上面的,要想访问到比较底层的与操作系统相关的就没办法了,只能由靠近操作系统的语言来实现。由于每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。要想对一个对象进行复制,就需要对clone方法覆盖。通过clone方法赋值的对象跟原来的对象同时独立存在。
在Java语言中,数据类型分为值类型(基本数据类型)和引用类型,值类型包括int、double、byte、boolean、char等简单数据类型,引用类型包括类、接口、数组等复杂类型。浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制。
浅克隆的一般步骤是:
1. 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法时会抛出CloneNotSupportedException异常),该接口为标记接口(不含任何方法);
2. 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象。
代码如下:
package com.itszt.test4;
/**
* 浅克隆
*/
public class Test {
public static void main(String[] args) {
Student stu1=new Student();
stu1.setNumber(159);
stu1.setAddr(new Address());
stu1.getAddr().setAddr("北京市");
Student stu2= (Student) stu1.clone();
stu2.setNumber(357);
stu2.getAddr().setAddr("上海市");
System.out.println(stu1);
System.out.println(stu2);
}
}
class Student implements Cloneable{
private int number;
private Address addr;
public Student() {
}
public void setNumber(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
@Override
protected Object clone() {
Student stu=null;
try {
stu = (Student)super.clone();//浅克隆
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
public Address getAddr() {
return addr;
}
@Override
public String toString() {
return "Student{" +
"number=" + number +
", addr=" + addr +
'}';
}
public void setAddr(Address addr) {
this.addr = addr;
}
}
class Address implements Cloneable{
private String addr;
public Address() {
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
protected Object clone() {
Address addr=null;
try {
addr= (Address) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return addr;
}
@Override
public String toString() {
return "Address{" +
"addr='" + addr + '\'' +
'}';
}
}
执行结果如下:
Student{number=159, addr=Address{addr='上海市'}}
Student{number=357, addr=Address{addr='上海市'}}
深层克隆是将引用对象里嵌套的引用对象再度克隆。接下来仅对上述代码增加了一行代码,就实现了深层克隆:
package com.itszt.test4;
/**
* 浅克隆
*/
public class Test {
public static void main(String[] args) {
Student stu1=new Student();
stu1.setNumber(159);
stu1.setAddr(new Address());
stu1.getAddr().setAddr("北京市");
Student stu2= (Student) stu1.clone();
stu2.setNumber(357);
stu2.getAddr().setAddr("上海市");
System.out.println(stu1);
System.out.println(stu2);
}
}
class Student implements Cloneable{
private int number;
private Address addr;
public Student() {
}
public void setNumber(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
@Override
protected Object clone() {
Student stu=null;
try {
stu = (Student) super.clone();//浅克隆
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
stu.addr= (Address) addr.clone();//深层克隆
return stu;
}
public Address getAddr() {
return addr;
}
@Override
public String toString() {
return "Student{" +
"number=" + number +
", addr=" + addr +
'}';
}
public void setAddr(Address addr) {
this.addr = addr;
}
}
class Address implements Cloneable{
private String addr;
public Address() {
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
protected Object clone() {
Address addr=null;
try {
addr= (Address) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return addr;
}
@Override
public String toString() {
return "Address{" +
"addr='" + addr + '\'' +
'}';
}
}
代码执行结果如下:
Student{number=159, addr=Address{addr='北京市'}}
Student{number=357, addr=Address{addr='上海市'}}