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} }})。
答案 0 :(得分:20)
Cloneable接口不包含任何成员。什么是使其成为通用的?
(如果Cloneable包含clone()方法,它会有意义 - 但是在java.lang.Object中声明了。)
编辑:clone()在java.lang.Object中,因为它有一个实现(它进行逐个字段的复制)。更好的设计是将.NET的MemberwiseClone()作为Object中的受保护方法,然后在接口本身中使用公共clone()方法。我不知道为什么没有选择这种设计。
(在.NET中,ICloneable不是通用的,因为它在泛型之前存在 - .NET泛型的不同性质阻止了以前的非泛型类型变得通用。)
然而,在Java和.NET中,“普通”克隆API通常被认为是一件坏事,因为它没有说明应该执行什么样的克隆深度。
答案 1 :(得分:9)
如果Cloneable
为Cloneable<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实现以复制源列表的内容。