一、clone方法
在实际编程中,经常会遇到从某个已有的对象A创建出另外一个与A具有相同状态的对象B,并且对B的修改不会影响到A的状态。在Java语言中,仅仅通过简单的赋值操作显然无法达到这个目的,而Java提供了一个简单有效的clone()方法来满足这个需求。
Java中的所有类默认都继承自Object类,而Object类中提供了一个clone()方法。这个方法的作用是返回一个Object对象的复制。这个复制返回的是一个新的对象而不是一个引用。以下是使用clone()方法的步骤:
(1)实现clone的类首先需要继承Cloneable接口。Cloneable接口实质上是一个标识接口,没有任何接口方法。
(2)在类中重写Object类中的clone()方法。
(3)在clone方法中调用super.clone()。无论clone类的继承结构是什么,super.clone()都会直接或间接调用java.lang.Object类的clone()方法。
(4)把浅复制的引用指向原型对象新的克隆体。
package com.haobi;
/*
* 使用clone()方法的步骤--浅复制
*/
class A implements Cloneable{//1、继承Cloneable接口
private int a = 0;
public int getInt() {
return a;
}
public void setInt(int i) {
a = i;
}
public void changeInt() {
a = 1;
}
public Object clone() {//2、重写Object类的clone()方法
Object o = null;
try {
o = (A)super.clone();//3、在clone()方法中调用super.clone()
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
public class TestClone {
public static void main(String[] args) {
A a = new A();
A b = (A)a.clone();//4、把浅复制的引用指向原型对象的克隆体
b.changeInt();
System.out.println("a:"+a.getInt());
System.out.println("b:"+b.getInt());
}
}
//程序输出结果如下:
a:0
b:1
在C++语言中,当开发人员自定义复制构造函数时,会存在浅复制和深复制之分。Java语言在重载clone()方法时也存在同样的问题,当类中只有一些基本的数据类型时,采用上述方法就可以了,但是当类中包含了一些对象时,就需要用到深复制了,实现方法是在对对象调用clone()方法完成复制后,接着对对象中的非基本类型的属性也调用clone()方法完成深复制。示例如下:
package com.haobi;
import java.util.Date;
/*
* 深复制
*/
class AA implements Cloneable{
private Date birth = new Date();
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public void changeDate() {
this.birth.setMonth(1);
}
public Object clone() {
AA a = null;
try {
a = (AA)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
//实现深复制
a.birth = (Date)this.getBirth().clone();
return a;
}
}
public class TestClone1 {
public static void main(String[] args) {
AA a = new AA();
AA b = (AA)a.clone();
b.changeDate();
System.out.println("a="+a.getBirth());
System.out.println("b="+b.getBirth());
}
}
//程序输出结果如下:
a=Fri Apr 12 15:53:04 CST 2019
b=Tue Feb 12 15:53:04 CST 2019
在编程时,首先检查类有无非基本类型(即对象)的数据成员。若没有,则返回super.clone()即可;若有,确保类中包含的所有非基本类型成员变量都实现了深复制。
Object o = super.clone();//先执行浅复制
o.attr = this,getAttr().clone();//然后对每一个对象attr执行以下语句
//最后返回o
需要注意的是,clone()方法的保护机制在Object中的clone()是被声明为protected的。以User类为例,通过声明为protected,就可以保证只有User类里面才能“克隆”User对象。
二、深复制和浅复制有什么区别?
浅复制(Shallow Clone):被复制对象的所有变量都含有与原来对象相同的值,而所有对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深复制(Deep Clone):被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制的新对象。而不再是原有的那些被引用的对象。换言之,深复制把复制的对象所引用的对象都复制了一遍。
以下例所示:
class Test{
public int i;
public StringBuffer s;
}