为什么Java的可克隆接口不是通用的?

时间:2008-12-23 08:55:28

标签: java generics

Java 5引入了泛型,它们被添加到java.lang包中的许多接口中。但是,Cloneable没有得到泛型。我想知道为什么?


编辑:在回复@Jon和@litb的答案以及@Earwicker的评论时,我在想Cloneable可能是:

public interface Cloneable<T> {
    public T clone();
}

此处T clone();覆盖Object.clone(),为其提供协变类型。我相信这仍然会向后兼容并提高类型安全性。那为什么不呢?


编辑2:从下面的答案(和评论)中可以看出,上面建议的界面会破坏向后兼容性。由于Object.clone()protected,在接口中重写它会强制所有实现者提供public实现,类设计者可能不想这样(即他们可能选择保留它{{1} }})。

5 个答案:

答案 0 :(得分:20)

Cloneable接口不包含任何成员。什么是使其成为通用的?

(如果Cloneable包含clone()方法,它会有意义 - 但是在java.lang.Object中声明了。)

编辑:clone()在java.lang.Object中,因为它有一个实现(它进行逐个字段的复制)。更好的设计是将.NET的MemberwiseClone()作为Object中的受保护方法,然后在接口本身中使用公共clone()方法。我不知道为什么没有选择这种设计。

(在.NET中,ICloneable不是通用的,因为它在泛型之前存在 - .NET泛型的不同性质阻止了以前的非泛型类型变得通用。)

然而,在Java和.NET中,“普通”克隆API通常被认为是一件坏事,因为它没有说明应该执行什么样的克隆深度。

答案 1 :(得分:9)

如果CloneableCloneable<T>,则无法执行此操作:

class A extends B implements Cloneable<A>

class B implements Cloneable<B>

您无法使用不同参数实现相同的界面,而A类会实现Cloneable<A>Cloneable<B>

答案 2 :(得分:6)

java.lang.Cloneable是一个标记界面。它仅用于此目的,以便Object.clone可以抛出异常,通过使用例如

来表示类不支持克隆
if(!(this instanceof Cloneable))
    throw...;

来自文档:

  

类Object的方法clone   执行特定的克隆操作。   首先,如果是这个对象的类   没有实现接口   克隆,然后一个   抛出CloneNotSupportedException。

没有方法。使它成为通用不会有任何用处。

答案 3 :(得分:3)

这并不能解决你的理论问题,而是处理实际案例:

Java 5具有协变返回值,并允许扩展方法的访问权限。因此,您可以在子类中适当地更改clone()的签名。

public class MyClass implements Cloneable {
    public MyClass clone(){ /* do the right stuff */ }
}

MyClass.clone()Object.clone()的正确覆盖,您不必编写强制转换。

答案 4 :(得分:1)

作为一个半相关的思想问题:创建一个接口(称之为ReallyCloneable)暴露clone()作为公共成员是否有用?

我的论点是,不,它不会。克隆性与具体的类实现密切相关。我想不出一个单一的用例,我可能会说“我有一个任意对象,我想要它的副本。”当前的问题是:你为什么要这份副本?

典型的答案是,您可以在不影响原件的情况下修改副本。但是,要做到这一点,你需要知道你持有什么类型的对象,否则你怎么知道要调用它来修改它?如果你知道,你就会知道它是否提供了一个公共的clone()方法。

但是,如果您正在编程接口,例如List,该怎么办?使用Collections框架,智能(递归)克隆(与字节级对象数据复制相比)将非常有用。但是可能存在不能支持此类操作的集合(例如由数据库支持的集合),因此您不能要求List公开公共clone()。这促使您实例化自己的具体List实现以复制源列表的内容。