java 克隆

java 克隆需实现 java.lang.Cloneable 接口并重写clone()方法;

@Override
 public Object clone() throws CloneNotSupportedException {
  return super.clone();
 }

 

如果不实现clone()方法则会报错误:

Exception in thread "main" java.lang.CloneNotSupportedException: com.domain.XXX
 at java.lang.Object.clone(Native Method)


先来看看JDK的解释:

java.lang.Cloneable
A class implements the Cloneable interface to indicate to the java.lang.Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class. 

Invoking Object's clone method on an instance that does not implement the Cloneable interface results in the exception CloneNotSupportedException being thrown. 

By convention, classes that implement this interface should override Object.clone (which is protected) with a public method. See java.lang.Object.clone() for details on overriding this method. 

Note that this interface does not contain the clone method. Therefore, it is not possible to clone an object merely by virtue of the fact that it implements this interface. Even if the clone method is invoked reflectively, there is no guarantee that it will succeed.

Since:
JDK1.0
Version:
1.17, 11/17/05
Author:
unascribed
See Also:
java.lang.CloneNotSupportedException
java.lang.Object.clone()

上面意思是:

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

如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常。

按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。请参阅 Object.clone(),以获得有关重写此方法的详细信息。

注意,此接口不 包含 clone 方法。因此,因为某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。

我们平时需要对某个对象进行操作,但是这个对象被两个地方操作,却都要使用最原始时候的对象。这个时候就需要Cloneable接口出现了。并且如果我们对象里面的属性还有非基本类型对象的话也需要实现此接口直到没有属性是非基本类型对象为止(深拷贝)
by : http://jiajun.iteye.com/blog/651201

 

详细示例: http://cqitcs02370236.cnblogs.com/archive/2006/04/23/382644.html

 

参考示例:

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分别克隆这两个类的对象,然后打印测试结果到控制台。
 
 
/**
 * Created by IntelliJ IDEA.
 * User: leizhimin
 * Date: 2007-9-20
 * Time: 19:40:44
 * 简单类克隆实现
 * 要实现克隆,必须实现Cloneable接口,这是一个标识接口,没有接口方法
 * 实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
 * 按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。
 */
public class CloneFooA implements Cloneable {
    private String strA;
    private int intA;
 
    public CloneFooA(String strA, int intA) {
        this.strA = strA;
        this.intA = intA;
    }
 
    public String getStrA() {
        return strA;
    }
 
    public void setStrA(String strA) {
        this.strA = strA;
    }
 
    public int getIntA() {
        return intA;
    }
 
    public void setIntA(int intA) {
        this.intA = intA;
    }
 
    /**
     * @return 创建并返回此对象的一个副本。
     * @throws CloneNotSupportedException
     */
    public Object clone() throws CloneNotSupportedException {
        //直接调用父类的clone()方法,返回克隆副本
        return super.clone();
    }
}
 
 
/**
 * Created by IntelliJ IDEA.
 * User: leizhimin
 * Date: 2007-9-20
 * Time: 19:59:55
 * 深度克隆对象,当类存在聚合关系的时候,克隆就必须考虑聚合对象的克隆
 */
public class CloneFooB implements Cloneable {
    private CloneFooA fooA;
    private Double douB;
 
    public CloneFooB(Double douB) {
        this.douB = douB;
    }
 
    public CloneFooB(CloneFooA fooA, Double douB) {
        this.fooA = fooA;
        this.douB = douB;
    }
 
    public CloneFooA getFooA() {
        return fooA;
    }
 
    public void setFooA(CloneFooA fooA) {
        this.fooA = fooA;
    }
 
    public Double getDouB() {
        return douB;
    }
 
    public void setDouB(Double douB) {
        this.douB = douB;
    }
 
    /**
     * 克隆操作
     *
     * @return 自身对象的一个副本
     * @throws CloneNotSupportedException
     */
    public Object clone() throws CloneNotSupportedException {
        //先调用父类的克隆方法进行克隆操作
        CloneFooB cloneFooB = (CloneFooB) super.clone();
        //对于克隆后出的对象cloneFooB,如果其成员fooA为null,则不能调用clone(),否则出空指针异常
        if (this.fooA != null)
            cloneFooB.fooA = (CloneFooA) this.fooA.clone();
 
        return cloneFooB;
    }
}
 
 
/**
 * Created by IntelliJ IDEA.
 * User: leizhimin
 * Date: 2007-9-20
 * Time: 19:52:01
 * 测试类:分别克隆CloneFooA和CloneFooB类,并打印克隆前后的结果.
 */
public class CloneDemo {
    public static void main(String args[]) throws CloneNotSupportedException {
        //CloneFooA克隆前
        CloneFooA fooA1 = new CloneFooA("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内存地址:相等!");
        else System.out.println("比较fooA1和fooA2内存地址:不相等!");
 
        System.out.println("-------------------------");
 
        //CloneFooB克隆前
        CloneFooB fooB1 = new CloneFooB(fooA1, new Double("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内存地址:相等!");
        else System.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 的基础上做了少许改动,内容如下:
 
public class CloneFooA implements Cloneable {
    private String strA;
    private int intA;
 
    public CloneFooA(String strA, int intA) {
        this.strA = strA;
        this.intA = intA;
    }
 
    public String getStrA() {
        return strA;
    }
 
    public void setStrA(String strA) {
        this.strA = strA;
    }
 
    public int getIntA() {
        return intA;
    }
 
    public void setIntA(int intA) {
        this.intA = intA;
    }
 
    /**
     * @return 创建并返回此对象的一个副本。
     * @throws CloneNotSupportedException
     */
    public Object clone() throws CloneNotSupportedException {
        //直接调用父类的clone()方法,返回克隆副本
        return super.clone();
    }
 
    /**
     * @return 返回运行时的对象
     */
    public CloneFooA getInstance(){
        return this;
    }
 
    public static void main(String args[]){
        CloneFooA fooA=new CloneFooA("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

by : http://lavasoft.blog.51cto.com/62575/43480/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值