专栏首页云霄雨霁Java--对象的克隆

Java--对象的克隆

因为Java方法中对象参数的传递是句柄(引用)传递,所以方法中对句柄的改动会影响到原对象。

很少调用一个方法来处理它的参数,在实际编程中也要避免改变参数的情况。但如果我们需要在一个方法的调用期间修改一个参数,且不打算修改外部实体,就应该在自己方法的内部制作一个那个参数的副本来保护那个参数。

制作对象副本需要使用clone()方法。这个方法在基础类Object 中定义成“protected”模式。所以在希望克隆的任何衍生类中,必须将其覆盖为“public”模式。例如,标准库类Vector 覆盖了 clone(),所以能为 Vector调用clone()。

class Int {
    private int i;
    public Int(int ii) { i = ii; }
    public void increment() { i++; }
    public String toString() {
        return Integer.toString(i);
    }
}
public class Cloning {
    public static void main(String[] args) {
        Vector v = new Vector();    //创建Vector
        for(int i = 0; i < 10; i++ )
            v.addElement(new Int(i));    //添加对象
        System.out.println("v: " + v);    //第一次输出  
        Vector v2 = (Vector)v.clone();    //创建Vector的复制
        for(Enumeration e = v2.elements();   
            e.hasMoreElements(); )    //对复制的Vector中的对象进行+1操作
        ((Int)e.nextElement()).increment();
        System.out.println("v: " + v);     //第二次输出
    }
} 

上面代码涉及到“深拷贝“和”浅拷贝“的问题。这个例子中由于别名问题,原Vector和拷贝的Vector都包含了相同的对象,即两个Vector是完全独立的,但其中容纳的东西相同,这就是”浅拷贝“。”浅拷贝“只拷贝本对象,该对象内部指向的其他对象,以及”其他对象“又指向的另外的对象都不拷贝。

若要“深拷贝”,必须在覆盖的clone()里采取附加的操作。 通常在调用 super.clone()后,为对象内每个句柄都明确调用一个 clone();否则那些句柄会别名变成原始对象的句柄。当然,必须保证对象内的每个句柄自身也都实现了“深拷贝”。

使类具有克隆能力:

因为Object类将clone()定义为”protected", 所以衍生类不做点什么的话,是无法具有克隆能力的(很简单,对象无法调用本类的protected方法)。

1、覆盖clone()方法为public. 

想要类可以克隆,记住两点:

  1. 几乎肯定要调用super.clone();
  2. 将clone()设置为public。

注意:因为Java不可能在衍生之后反而缩小方法的访问范围,所以一旦对象变得可以克隆,从它衍生的任何东西都是可以克隆的。(下面会有一种特殊机制关闭克隆能力)

2、实现Cloneable接口

Cloneable接口是空的,我们不需要为它实现任何方法。它的存在有两个原因:

  • 可能有一个上溯造型句柄指向一个基础类型,而且不知道它是否真的能克隆那个对象。在这种情况下,可用instanceof 关键字调查句柄是否确实同一个能克隆的对象连接。
  • 考虑到我们可能不愿所有对象类型都能克隆。所以Object.clone()会验证一个类是否真的是实现了Cloneable 接口。若答案是否定的,则“掷”出一个 CloneNotSupportedException违例。

所以在一般情况下,我们必须将“implement Cloneable”作为对克隆能力提供支持的一部分。

经过上面两步,就可以创建自己的可克隆的类:

class MyObject implements Cloneable {
    int i;
    MyObject(int ii) { i = ii; }
    public Object clone() {
        Object o = null;
        try {
            o = super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("MyObject can't clone");
        }
        return o;
    }
    public String toString() { return Integer.toString(i); }
}

 消除克隆能力:

  1. 不实现 Cloneable 来试着防止克隆,并覆盖clone(),以产生一个违例。这样,从它衍生出来的类的clone()方法调用super.clone()时会抛出异常。
  2. 将类设为final,从而防止克隆。若clone()尚未被我们的任何一个上级类覆盖,这一设想便不会成功。 若已被覆盖,那么再一次覆盖它,并“掷”出一个 CloneNotSupportedException(克隆不支持)违例。为担保克隆被禁止,将类设为final是唯一的办法。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java--集合类之Vector、BitSet、Stack、Hashtable

    SuperHeroes
  • Java--类和对象之句柄、作用域

    SuperHeroes
  • 删数问题

    SuperHeroes
  • 混合云和多云管理不再难:基础架构即代码来帮忙

    随着运维流程变得越来越灵活,IT团队面临着越来越大的复杂度。当应用动态改变时,可以使用敏捷或者持续应用开发。但是当IT资源本身动态变化的时候怎么办呢多云和混合云...

    静一
  • HttpContext.Cache属性

          HttpContext基于HttpApplication的处理管道,由于HttpContext对象贯穿整个处理过程,所以,可以从HttpApplic...

    用户1055830
  • Android项目实战(十一):moveTaskToBack(boolean ) 方法的使用

    听着music睡
  • 低功耗物联网的诞生:第二次无线革命

    物联网对众多技术行业造成了剧烈的冲击,其中就包括电信。以前,电信行业的发展方向似乎十分明确:不断提高数据的无线传输速率。所有的供应商都或多或少的在追求这个相同的...

    未来守护者
  • 如何修改Apache默认监听的80端口

    相同目录下的apache2.conf,文件内有自描述的注释,该文件是apache配置文件的入口:

    Jerry Wang
  • 将你的博客升级为 PWA 渐进式Web离线应用

    PWA 全称 Progressive Web Apps(渐进式 Web 应用程序),旨在使用现有的 Web 技术提供用户更优的使用体验。 基本要求

    ihoey
  • 资源 | 机器学习新框架Propel:使用JavaScript做可微分编程

    机器之心

扫码关注云+社区

领取腾讯云代金券