12

Cloneable在Java中天生就坏了。具体来说,我对接口的最大问题是它需要一个不定义方法本身的方法行为。因此,如果遍历Cloneable列表,则必须使用反射来访问其定义的行为。但是,在 Java 8 中,我们现在有了默认方法,现在我问clone()为什么Cloneable.

我理解为什么接口不能默认 Object 方法,但是,这是一个明确的设计决定,因此可以进行例外处理。

我有点设想弃用Object.clone()并将其内部代码更改为:

if(this instanceof Cloneable) {
    return ((Cloneable) this).clone();
}
else {
    throw new CloneNotSupportedException();
}

并继续使用任何魔法clone()作为Cloneable. 这并不能真正解决clone()仍然很容易错误实施的问题,但这本身就是另一个讨论。

据我所知,这种变化将完全向后兼容:

  1. 当前覆盖clone()但未实现的类Cloneable(为什么?!)在技术上仍然可以(即使在功能上是不可能的,但这与以前没有什么不同)。
  2. 当前覆盖clone()但确实实现的类Cloneable在其实现中仍将发挥相同的作用。
  3. 当前未覆盖clone()但已实现Cloneable(为什么?!)的类现在将遵循规范,即使它在功能上并不完全正确。
  4. 那些使用反射和引用的Object.clone()仍然可以正常工作。
  5. super.clone()即使引用Object.clone().

更不用说这将解决一个巨大的问题Cloneable。虽然繁琐并且仍然很容易错误地实现,但它可以解决接口的一个巨大的面向对象问题。

我能看到的唯一问题是那些实现Cloneable没有义务覆盖的问题clone(),但这与以前没有什么不同。

有没有内部讨论过,但从未实现?如果是这样,为什么?如果是因为接口不能默认 Object 方法,那么在这种情况下创建异常是否有意义,因为所有继承的对象Cloneable都在期待clone()

4

2 回答 2

8
于 2015-12-06T22:42:21.540 回答
6

我的经验可能远非主流,但我使用clone()并支持Cloneable. 将其作为注释可能会更好,但Cloneable在注释之前很久就出现了。我的观点是这Cloneable是一件低级的事情,没有人应该做类似obj instanceof Cloneable. 如果您Cloneable在某些业务逻辑中使用,最好声明您自己的接口或抽象类,这些接口或抽象类公开clone()并在您的所有业务逻辑对象中实现它。有时您可能不想clone()实际公开,而是创建自己的clone()内部使用方法。

例如,假设您有一个命名对象的层次结构,其中名称在构造后无法更改,但您希望允许使用新名称克隆它们。您可以像这样创建一些抽象类:

public abstract class NamedObject implements Cloneable {
    private String name;

    protected NamedObject(String name) {
        this.name = name;
    }

    public final String getName() {
        return name;
    }

    public NamedObject clone(String newName) {
        try {
            NamedObject clone = (NamedObject)super.clone();
            clone.name = newName;
            return clone;
        }
        catch(CloneNotSupportedException ex) {
            throw new AssertionError();
        }
    }
}

这里即使你实现Cloneable了,你也想使用clone(),但又不想公开。相反,您提供了另一种方法,允许使用另一个名称进行克隆。因此,拥有 public clone()inCloneable会不必要地污染类的公共接口。

我使用的另一种情况CloneableSpliterator.trySplit(). 请参阅简单拆分器的实现,它返回给定数量的常量对象。它有四个特化(对象、整数、长整数和双精度数),但由于clone()trySplit()只能在超类中实现一次。同样,我不想暴露clone(),我只想自己使用它。

所以总而言之,clone()在接口中没有方法Cloneable实际上更灵活,因为它允许我决定是否要公开它。

于 2015-12-07T04:09:10.747 回答