【问题标题】:Overriding Clone() method in Java when superclass is not Clonable当超类不可调用时,在 Java 中覆盖 Clone() 方法
【发布时间】:2020-01-25 22:02:42
【问题描述】:

How to clone a Java object with the clone() method

我有一个关于在 java 中为类正确实现 clone() 方法的问题。 我知道这是不好的做法,但我需要在考试中知道这一点。 在上面的讨论中,他们说要调用super.clone() - 但我不明白如果超级函数没有实现 Clonable 会发生什么。 例如,假设我有一个扩展 Y 的类 X。X 实现了 Clonable 而 Y 没有。 Y 的clone() 方法应该抛出异常。那么在这种情况下我们该怎么办呢?

我能找到的所有解释都假设所有超类都实现了 Clonable,或者至少我是这么理解的..

编辑:

请查看此代码:

public class Employee implements Cloneable {

private String name;

public Employee(String name) {
    this.name = name;
}

public String getName() {
    return name;
}

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

public static void main(String[] args) {
    Employee emp = new Employee("Abhi");
    try {
        Employee emp2 = (Employee) emp.clone();
        System.out.println(emp2.getName());
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
}

}

取自这里:https://www.javacodegeeks.com/2018/03/understanding-cloneable-interface-in-java.html

在许多教程中都可以找到类似的代码。

当超类(在本例中为 Object)未实现 Clonable 时,为什么他们可以使用 super.clone() - 这会导致异常。

【问题讨论】:

  • 如果 'superclass is not Clonable' 意味着超类没有实现 'Clonable' 接口 - 将没有 super.clone() 方法,因此您将无法调用它。那么问题是什么?
  • 那么在这种情况下我该如何克隆呢?如何覆盖 clone() 方法?
  • @AlexChernyshev 是一个super.clone(),因为它是在Object上声明的;如果对象确实实现了Clonable,它就不会起作用
  • @AlexChernyshev clone() is a method of Object。因此,Java 中的每个对象都有一个clone()-方法(不仅仅是有问题的行为)。
  • @Turing85 很多人认为“Java 已损坏”,所以呢?让我们留在话题上。

标签: java cloning


【解决方案1】:

如果你有这个结构:

class Y {}

class X extends Y implements Cloneable {
    @Override
    public X clone() {
        try {
            return (X) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        } 
    }
}

然后在X 的实例上克隆将正常工作。 它不适用于Y 的直接实例,因为它们未被声明为可克隆。但是X 上的Cloneable 接口是默认clone() 实现机制的一个指标,它们应该可以工作。

或者

只要不依赖clone() 的默认实现,您也可以拥有一个具有有效clone() 方法的不可克隆类。

例如:

class Y {
    @Override
    public Y clone() {
        // Don't call super.clone() because it will error
        return new Y(...); // whatever parameters
    }
}

但是,使用 this 机制,如果您从Y 的子类调用super.clone(),您将获得Y 的实例,这可能不是您想要的。

正如其他人所指出的,Cloneable 机制笨拙且令人困惑,通常使用 new 复制机制更容易使用。

【讨论】:

  • 为什么它适用于 X 的实例?您编写的克隆方法将导致异常。你说的默认实现是什么意思?
  • 我的答案中的克隆方法可以正常工作而不会出错。 clone() 的默认实现是从调用super.clone() 一直到Object 类,只要您要克隆的实例实现Clonable,它就可以工作。
  • @khelwood 我在 Java API 中读到,当一个类没有实现 Clonable 时,它​​的 clone 方法会导致异常。所以你的意思是有一个不同的实现?
  • @khelwood 是的(已经删除了评论)。但是,这仅在 Y 本身不覆盖 clone() 时才有效,例如return new Y();.
  • @PhysicsPrincess 如果X实现了Clonable,那么你可以调用super.clone()并且它不会抛出异常,即使Y是不可克隆的,因为对象你正在克隆仍然是X的一个实例,一个可克隆的类。
【解决方案2】:

Cloneable-interface 通常是regarded as broken (and won't be fixed)。在核心,争论围绕着clone() is a method defined on Object,而不是接口Cloneable的方法。

我根本不建议使用它。更好的解决方案是提供copy-constructors。如果一个人没有能力完全重新创建一个父类对象,那么克隆是不可能的。

重构提供的代码会导致类似这样的结果:

public class Employee implements Cloneable {

    private String name;

    public Employee(String name) {
        this.name = name;
    }

    public Employee(Employee that) {
        this.name = that.name;
    }

    public static void main(String[] args) {
        Employee emp = new Employee("Abhi");
        Employee emp2 = new Employee(emp);
        System.out.println(emp2.getName());
    }

    public String getName() {
        return name;
    }
}

对您的代码的备注:

public class Employee {
    public Object clone()throws CloneNotSupportedException{  
        return (Employee)super.clone();  
    }
}

类型转换是多余的,因为方法返回 Object

【讨论】:

  • 我知道复制构造函数,但我问是因为我们在课堂上也需要知道这一点
  • 然后告诉您的教授/主管/老师Cloneable 已(过去和将来)已损坏,不应使用。如果她/他问为什么,请将她/他指向我提供的链接。供参考:Josh Bloch 是 Sun Microsystems 的一名软件工程师,他实现了 Collections 框架等。
  • 当然,Java 是 Java,其中对象不需要明确的所有者,诀窍通常是根本不必克隆任何东西。最好可以将类设置为不可变的,这样克隆就完全是多余的(顺便说一句,您仍然可以使用返回已更改对象实例的方法)。
猜你喜欢
  • 2018-06-10
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 1970-01-01
  • 2015-06-24
  • 1970-01-01
相关资源
最近更新 更多