Java克隆应用_Java克隆(Clone)的应用

简介:

Java克隆(Clone)是Java语言的特性之一,但在实际中应用比较少见。但有时候用克隆会更方便更有效率。

对于克隆(Clone),Java有一些限制:

1、被克隆的类必须自己实现Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。Cloneable 接口实际上是个标识接口,没有任何接口方法。

2、实现Cloneable接口的类应该使用公共方法重写 Object.clone(它是受保护的)。某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。

3、在Java.lang.Object类中克隆方法是这么定义的:

protected Object clone()

throws CloneNotSupportedException

创建并返回此对象的一个副本。表明是一个受保护的方法,同一个包中可见。

按照惯例,返回的对象应该通过调用 super.clone 获得。

引题:

举个例子说吧,现在有一个对象比如叫foo,你需要在创建当前对象的一个副本作为存根你能怎么做?

假如你不用Clone,那么你可以先new一个对象foo1:Foo foo1=new Foo(),然后用foo给foo1对象set值,这样就得到foo的副本foo1;除此之外,别无选择。

这样说,也许有人会觉得说的过于绝对了,不过事实如此啊。

要产生一个副本,那副本要不要内存?----当然要了,那就对了!既然需要内存,(不克隆的情况下)你不new还有什么办法呢?请大家时刻铭记对象是Java运行时产生的,驻留在计算机内存中。

常见错误:

下面我澄清几个初学者容易犯迷糊的错误,同样的问题,产生foo对象的副本:

1、Foo foo1=new Foo();

foo1=foo;

然后就想当然的认为副本foo1生成了!

错误原因:foo1没错是申请了内存,但是执行foo1=foo后,foo1就不在指向刚申请的内存区域了,转而指向foo对象的内存区域,这时候,foo1、foo指向了同一内存区域。刚才new的操作制造一堆垃圾等着JVM回收。

2、Foo foo1=foo;

错误原因:还是两个变量都指向了同一块内存。

3、有些老鸟更厉害一些:在Foo中定义一个返回自身的方法:

public Foo getInstance(){

return this;

}

然后,Foo foo1=foo.getInstance();

错误原因:同上,主要还是没有重新开辟内存,this在对象里是什么?----就是对象自己的引用!那么getInstance()自然返回的就是对象自己,反正又是两个对象穿了一条裤子----***,哈哈。错得心服口服吧。为了节省篇幅,我在最后写个例子,留给那些对此有异议的人看。

引入克隆

看了这么多方法都不行,还很麻烦!干脆用克隆吧,简单明了。

废话不说了,看例子:

定义两个类CloneFooA、CloneFooB,然后写个测试类CloneDemo分别克隆这两个类的对象,然后打印测试结果到控制台。

/*** 简单类克隆实现

* 要实现克隆,必须实现Cloneable接口,这是一个标识接口,没有接口方法

* 实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。

* 按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。*/publicclassCloneFooAimplementsCloneable {privateString strA;privateintintA;publicCloneFooA(String strA,intintA) {this.strA=strA;this.intA=intA;

}publicString getStrA() {returnstrA;

}publicvoidsetStrA(String strA) {this.strA=strA;

}publicintgetIntA() {returnintA;

}publicvoidsetIntA(intintA) {this.intA=intA;

}/***@return创建并返回此对象的一个副本。

*@throwsCloneNotSupportedException*/publicObject clone()throwsCloneNotSupportedException {//直接调用父类的clone()方法,返回克隆副本returnsuper.clone();

}

}

/*** 深度克隆对象,当类存在聚合关系的时候,克隆就必须考虑聚合对象的克隆*/publicclassCloneFooBimplementsCloneable {privateCloneFooA fooA;privateDouble douB;publicCloneFooB(Double douB) {this.douB=douB;

}publicCloneFooB(CloneFooA fooA, Double douB) {this.fooA=fooA;this.douB=douB;

}publicCloneFooA getFooA() {returnfooA;

}publicvoidsetFooA(CloneFooA fooA) {this.fooA=fooA;

}publicDouble getDouB() {returndouB;

}publicvoidsetDouB(Double douB) {this.douB=douB;

}/*** 克隆操作

*

*@return自身对象的一个副本

*@throwsCloneNotSupportedException*/publicObject clone()throwsCloneNotSupportedException {//先调用父类的克隆方法进行克隆操作CloneFooB cloneFooB=(CloneFooB)super.clone();//对于克隆后出的对象cloneFooB,如果其成员fooA为null,则不能调用clone(),否则出空指针异常if(this.fooA!=null)

cloneFooB.fooA=(CloneFooA)this.fooA.clone();returncloneFooB;

}

}

/*** 测试类:分别克隆CloneFooA和CloneFooB类,并打印克隆前后的结果.*/publicclassCloneDemo {publicstaticvoidmain(String args[])throwsCloneNotSupportedException {//CloneFooA克隆前CloneFooA fooA1=newCloneFooA("FooA",11);

System.out.println("CloneFooA的对象克隆前对象fooA1值为:"+fooA1.getStrA()+","+fooA1.getIntA());//CloneFooA克隆后CloneFooA fooA2=(CloneFooA) fooA1.clone();

System.out.println("CloneFooA的对象克隆后对象fooA2值为:"+fooA2.getStrA()+","+fooA2.getIntA());//比较fooA1和fooA2内存地址if(fooA1==fooA2) System.out.println("比较fooA1和fooA2内存地址:相等!");elseSystem.out.println("比较fooA1和fooA2内存地址:不相等!");

System.out.println("-------------------------");//CloneFooB克隆前CloneFooB fooB1=newCloneFooB(fooA1,newDouble("33"));

System.out.println("CloneFooB的对象克隆前对象fooB1值为:"+fooB1.getFooA().getStrA()+","+fooB1.getFooA().getIntA()+"|"+fooB1.getDouB());//CloneFooB克隆后CloneFooB fooB2=(CloneFooB) fooB1.clone();

System.out.println("CloneFooB的对象克隆前对象fooB2值为:"+fooB2.getFooA().getStrA()+","+fooB2.getFooA().getIntA()+"|"+fooB2.getDouB());if(fooA1==fooA2) System.out.println("比较fooB1和fooB2内存地址:相等!");elseSystem.out.println("比较fooB1和fooB2内存地址:不相等!");

}

}

运行结果:

CloneFooA的对象克隆前对象fooA1值为: FooA,11

CloneFooA的对象克隆后对象fooA2值为: FooA,11

比较fooA1和fooA2内存地址:不相等!

-------------------------

CloneFooB的对象克隆前对象fooB1值为: FooA,11 | 33.0

CloneFooB的对象克隆前对象fooB2值为: FooA,11 | 33.0

比较fooB1和fooB2内存地址:不相等!

Process finished with exit code 0

反面教材:

最后,我给出我上面提出到最后要给出的反面例子。

随便写一个,在CloneFooA 的基础上做了少许改动,内容如下:

publicclassCloneFooAimplementsCloneable {privateString strA;privateintintA;publicCloneFooA(String strA,intintA) {this.strA=strA;this.intA=intA;

}publicString getStrA() {returnstrA;

}publicvoidsetStrA(String strA) {this.strA=strA;

}publicintgetIntA() {returnintA;

}publicvoidsetIntA(intintA) {this.intA=intA;

}/***@return创建并返回此对象的一个副本。

*@throwsCloneNotSupportedException*/publicObject clone()throwsCloneNotSupportedException {//直接调用父类的clone()方法,返回克隆副本returnsuper.clone();

}/***@return返回运行时的对象*/publicCloneFooA getInstance(){returnthis;

}publicstaticvoidmain(String args[]){

CloneFooA fooA=newCloneFooA("aa",11);

System.out.println(fooA.getStrA()+""+fooA.getIntA());

CloneFooA fooA1=fooA.getInstance();

System.out.println(fooA1.getStrA()+""+fooA1.getIntA());if(fooA==fooA1) System.out.println("fooA和fooA1内存地址相等!");

System.out.println("-------------------------");//改变后fooA或者fooA1中任何一个,看看另外一个是否会改变fooA1.setStrA("bb");

System.out.println(fooA.getStrA()+""+fooA.getIntA());

System.out.println(fooA1.getStrA()+""+fooA1.getIntA());if(fooA==fooA1) System.out.println("fooA和fooA1内存地址相等,改变fooA1后,fooA的值也跟着变化了");

}

}

运行结果:

aa  11

aa  11

fooA和fooA1内存地址相等!

-------------------------

bb  11

bb  11

fooA和fooA1内存地址相等,改变fooA1后,fooA的值也跟着变化了

Process finished with exit code 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值