java clone
有时我们确实需要clone一个对象,最好的方法还是使用Object的clone方法,由jdk调用native方法来实现,这样效率比较高。先来个shallow clone,再来deep clone。
shallow clone
代码如下:
待clone的对象
package practisejava.others.clone;
/**
* 待clone的对象,必须实现Cloneable这个tag interface
*/
public class ObjectToClone implements Cloneable{
private int i=0;
public void setNum(int i){
this.i=i;
}
public int getNum(){
return this.i;
}
public void tellNum(){
System.out.println("the number is "+i);
}
// 重写Object的clone
public Object clone() throws CloneNotSupportedException {
return (ObjectToClone)super.clone();
}
}
clone测试
package practisejava.others.clone;
/**
* 测试clone是否成功
*/
public class CloneTest {
public static void main(String[] args) {
ObjectToClone otc = new ObjectToClone();
otc.setNum(888);
// 开始clone了!
ObjectToClone cloneObject = null;
try {
cloneObject = (ObjectToClone) otc.clone();
} catch (CloneNotSupportedException ex) {
System.out.println("Sorry,Clone Not Supported!");
}
// 测试clone是否成功
if(cloneObject!=null){
System.out.println("before clone");
System.out.println("ObjectToClone get number : " + otc.getNum()+"/n");
System.out.println("after clone");
System.out.println("ObjectToClone get number : " + otc.getNum());
cloneObject.setNum(999);
System.out.println("CloneObject get number : " + cloneObject.getNum());
}
}
}
执行结果
before clone
ObjectToClone get number : 888
after clone
ObjectToClone get number : 888
CloneObject get number : 999
从运行结果看,修改了clone体的值并没有影响到原来被clone体的值,哈哈,clone成功。高兴得太早了,ObjectToClone里只有简单的非引用属性,如果有引用的属性,还能成吗?答案是否定的!看下面的例子:
被clone对象引用的对象
package practisejava.others.shallowclone;
public class ReferencedObject {
private int i = 0;
public ReferencedObject(int i) {
this.i = i;
}
public void doubleValue(){
this.i = 2*this.i;
}
public int getNumber(){
return this.i;
}
}
待clone对象
package practisejava.others.shallowclone;
/**
* 必须实现Cloneable接口,否则调用函数的clone方法时会报CloneNotSupportedException错
*/
public class ObjectForShallowClone implements Cloneable{
private int i = 0;
private ReferencedObject rf = null;
public void setNum(int i) {
this.i = i;
}
public void setReferencedObject(ReferencedObject rf){
this.rf = rf;
}
public int getNumber(){
return this.i;
}
public ReferencedObject getReferencedObject(){
return this.rf;
}
// 重写Object的clone
public Object clone() throws CloneNotSupportedException {
return (ObjectForShallowClone)super.clone();
}
}
clone测试
package practisejava.others.shallowclone;
/**
* clone测试
*/
public class CloneTest {
public static void main(String[] args) {
ObjectForShallowClone ofsc = new ObjectForShallowClone();
ofsc.setNum(888);
ofsc.setReferencedObject(new ReferencedObject(1));
// 开始clone了!
ObjectForShallowClone deepCloneObject = null;
try {
deepCloneObject = (ObjectForShallowClone) ofsc.clone();
} catch (CloneNotSupportedException ex) {
System.out.println("Sorry,Clone Not Supported!");
}
// 测试clone是否成功
if(deepCloneObject!=null){
System.out.println("before clone");
System.out.println("ObjectForShallowClone get number : " + ofsc.getNumber());
System.out.println("ObjectForShallowClone ReferencedObject get number : "+ofsc.getReferencedObject().getNumber()+"/n");
deepCloneObject.setNum(999);
deepCloneObject.getReferencedObject().doubleValue();
System.out.println("after clone");
System.out.println("ObjectForShallowClone get number : " + ofsc.getNumber());
System.out.println("ObjectForShallowClone ReferencedObject get number : " + ofsc.getReferencedObject().getNumber());
System.out.println("CloneObject get number : " + deepCloneObject.getNumber());
System.out.println("CloneObject ReferencedObject get number : " + deepCloneObject.getReferencedObject().getNumber());
}
}
}
运行结果如下:
before clone
ObjectForShallowClone get number : 888
ObjectForShallowClone ReferencedObject get number : 1
after clone
ObjectForShallowClone get number : 888
ObjectForShallowClone ReferencedObject get number : 2
CloneObject get number : 999
CloneObject ReferencedObject get number : 2
显然,修改了clone对象的引用对象的值后,被clone对象引用对象的值也随之改变。这不是我们想要的效果,改进的方法就是deep clone。
deep clone
被clone对象引用的对象(比shallow clone多加了clone的方法)
package practisejava.others.deepclone;
public class ReferencedObject implements Cloneable{
private int i = 0;
public ReferencedObject(int i) {
this.i = i;
}
public void doubleValue(){
this.i = 2*this.i;
}
public int getNumber(){
return this.i;
}
// 重写clone的方法
public Object clone() throws CloneNotSupportedException {
return (ReferencedObject)super.clone();
}
}
待clone对象(在clone方法里同时clone引用对象)
package practisejava.others.deepclone;
import practisejava.others.deepclone.ReferencedObject;
public class ObjectForDeepClone implements Cloneable{
private int i = 0;
private ReferencedObject rf = null;
public void setNum(int i) {
this.i = i;
}
public void setReferencedObject(ReferencedObject rf){
this.rf = rf;
}
public int getNumber(){
return this.i;
}
public ReferencedObject getReferencedObject(){
return this.rf;
}
// 重写Object的clone
public Object clone() throws CloneNotSupportedException {
ObjectForDeepClone cloneObject = (ObjectForDeepClone)super.clone();
// 调用引用对象的clone方法
if(rf!=null){
ReferencedObject rfClone = (ReferencedObject)rf.clone();
cloneObject.setReferencedObject(rfClone);
}
return cloneObject;
}
}
clone测试
package practisejava.others.deepclone;
public class CloneTest {
public static void main(String[] args) {
ObjectForDeepClone ofdc = new ObjectForDeepClone();
ofdc.setNum(888);
ofdc.setReferencedObject(new ReferencedObject(1));
// 开始clone了!
ObjectForDeepClone deepCloneObject = null;
try {
deepCloneObject = (ObjectForDeepClone) ofdc.clone();
} catch (CloneNotSupportedException ex) {
System.out.println("Sorry,Clone Not Supported!");
}
// 测试clone是否成功
if(deepCloneObject!=null){
System.out.println("before clone");
System.out.println("ObjectForDeepClone get number : " + ofdc.getNumber());
System.out.println("ObjectForDeepClone ReferencedObject get number : "+ofdc.getReferencedObject().getNumber()+"/n");
deepCloneObject.setNum(999);
deepCloneObject.getReferencedObject().doubleValue();
System.out.println("after clone");
System.out.println("ObjectForDeepClone get number : " + ofdc.getNumber());
System.out.println("ObjectForDeepClone ReferencedObject get number : " + ofdc.getReferencedObject().getNumber());
System.out.println("CloneObject get number : " + deepCloneObject.getNumber());
System.out.println("CloneObject ReferencedObject get number : " + deepCloneObject.getReferencedObject().getNumber());
}
}
}
运行结果:
before clone
ObjectForDeepClone get number : 888
ObjectForDeepClone ReferencedObject get number : 1
after clone
ObjectForDeepClone get number : 888
ObjectForDeepClone ReferencedObject get number : 1
CloneObject get number : 999
CloneObject ReferencedObject get number : 2
Clone通常有两种类型即浅clone和深clone。首先,分析一下两种的不同。浅clone和深clone都是clone,它们本质区别是对象内部的成员属性(非原生类型属性,如int等)在clone时是否处理为引用。如果仍然保留为引用,则称为浅clone,反之称为深clone。其实这两个概念也是相对的概念。在处理上它们有点区别,浅clone方式得到clone对象即可,深clone方式在得到clone对象后,还需要对引用的成员属性进行“clone”处理。从这个层次上说,深clone并没有什么特别地困难,简单讲就是创建好对象,再设置一些成员属性。