【问题标题】:Question about the Cloneable interface and the exception that should be thrown关于Cloneable接口和应该抛出的异常的问题
【发布时间】:2011-02-22 17:47:55
【问题描述】:

Java 文档说:

一个类实现了 Cloneable 接口指示 Object.clone() 方法 这种方法制作一个合法的 实例的场对场副本 那个班级。

在一个对象上调用对象的克隆方法 没有实现的实例 可克隆界面导致 异常 CloneNotSupportedException 被扔了。

按照惯例,实现的类 这个接口应该覆盖 Object.clone (受保护) 一种公共方法。参见 Object.clone() 有关覆盖此方法的详细信息。

请注意,此接口不 包含克隆方法。所以, 无法克隆对象 仅仅因为它 实现这个接口。即使 反射调用克隆方法, 不能保证它会 成功。

我有这个UserProfile 类:

public class UserProfile implements Cloneable {
    private String name;
    private int ssn;
    private String address;

    public UserProfile(String name, int ssn, String address) {
        this.name = name;
        this.ssn = ssn;
        this.address = address;
    }

    public UserProfile(UserProfile user) {
        this.name = user.getName();
        this.ssn = user.getSSN();
        this.address = user.getAddress();
    }

    // get methods here...

    @Override
    public UserProfile clone() {
        return new UserProfile(this);
    }
}

为了测试 porpuses,我在 main() 中执行此操作:

UserProfile up1 = new UserProfile("User", 123, "Street");
UserProfile up2 = up1.clone();

到目前为止,编译/运行没有问题。现在,根据我对文档的理解,从UserProfile 类中删除implements Cloneable 应该会在up1.clone() 调用中引发异常,但它不会。

我在这里读到过 Cloneable 界面已损坏,但我真的不知道这意味着什么。我错过了什么吗?

【问题讨论】:

  • Cloneable 是有问题的,因为 Cloneable 接口没有 clone() 方法,你要么需要知道实现 clone() 方法的特定类型(在这种情况下你是具体类型,所以你可以使用复制构造函数)或者你必须使用反射。任何需要反射才能正常工作的 API 都可能被描述为损坏。
  • 注意:在clone方法中,不要调用构造函数,而是调用(UserProfile)super.clone()。见java.sun.com/javase/6/docs/api/java/lang/…“按惯例……”

标签: java exception interface clone cloneable


【解决方案1】:

现在,根据我对文档的理解,从 UserProfile 类中删除 implements Cloneable 应该会在 up1.clone() 调用中抛出异常,但事实并非如此。

只要你的类仍然有 clone() 方法的实现,当你调用它时当然不会抛出异常 - 它就像任何其他方法一样工作,不涉及特殊魔法。

Object 类中的 clone() 的实现是引发异常的原因,但您已经覆盖了该方法。

【讨论】:

  • 至少涉及一些魔法,因为当通过 super.clone() 调用时,Object.clone() 不会抛出该异常。但除此之外,我同意。
  • Object.clone() 检查对象是否是实现Cloneable 的类的实例,如果不是则抛出异常。不需要特殊的魔法(例如编译器的特殊处理)......
【解决方案2】:

这意味着如果你实现了Cloneable并省略了clone()方法,然后调用了clone()方法,就会抛出异常。

编辑:之前可能被提及过 10 亿次,但是

不要使用克隆方法!

如果您需要克隆功能,请提供一个复制构造函数。

接口被称为损坏,因为它不会强制您实现 clone()(它应该这样做)。

【讨论】:

  • 如果我用自己的实现覆盖它,不使用克隆方法的论据是什么?
  • 恕我直言,仅实现复制构造函数可能会导致其他继承问题。我不明白为什么一个应该比另一个更糟。在那种情况下,为什么不坚持使用标准的 Cloneable 呢?至少大多数开发人员都知道它的缺点并且可以处理它们。
  • 据我所见,我在我的类中重写了 clone 方法,它所做的只是调用复制构造函数。这有什么问题?
  • @Nazgulled 抱歉,没有看到复制构造函数。但是为什么你的 clone 方法不直接调用 super.clone() 呢?
【解决方案3】:

我同意这两个答案并添加一些内容:接口就像一个“标签”,表示您的类实现了 clone()。当您不知道对象类型时,这在类似 api 的方法中很有用。然后就可以写了

if (myobj instanceof Cloneable) { dosmthng(); }

【讨论】:

  • 您应该使用instanceof 而不是is
  • 更正了,我把 C# 搞混了。谢谢。
猜你喜欢
  • 2016-06-02
  • 2011-01-22
  • 1970-01-01
  • 1970-01-01
  • 2013-03-14
  • 1970-01-01
  • 2017-10-04
  • 2013-05-20
  • 1970-01-01
相关资源
最近更新 更多