所以,假设我们有一个简单的界面
public interface ICopyable<T> {
void copyFrom(T original);
}
这基本上添加了一个带参数化类型的copyFrom方法。你有一个扩展它的界面:
public interface ISomeObject<T> extends ICopyable<T> {
String getType();
}
界面并没有添加任何有价值的东西,当然除了它的类型,但让我们假装有一些有用的方法。这个想法仍然是相同的 - 这个接口的所有对象都有一个getType()方法,他们可以将一个相同类型的对象从一个复制到另一个。
现在让我们有两个这个接口的实现,第二个实现继承自第一个:
public static class ActualObject1 implements ISomeObject<ActualObject1> {
Object data1;
@Override public void copyFrom(final ActualObject1 original) {
this.data1 = original.data1;
}
@Override public String getType() {
return this.getClass().getSimpleName();
}
}
public static class ActualObject2 extends ActualObject1 {
Object data2;
@Override public void copyFrom(final ActualObject1 original) {
super.copyFrom(original);
// oh no! i've just realized that i'm not copying the ActualObject2!
}
}
所以第二个对象(ActualObject2)应该扩展ActualObject1,但如果以这种方式完成它就无法实现正确的“copyFrom”方法,因为第一个类只为自己实现了接口ISomeObject。它显然想以某种方式做到允许将ActualObject2相互复制。但是如何?
它不能只声明实现ISomeObject,因为它会与它的父实现类型冲突。 所以你可能想做那样的事情吗?
public static class ActualObject1<T extends ActualObject1> implements ISomeObject<T> {
Object data1;
@Override public void copyFrom(final ActualObject1 original) {
this.data1 = original.data1;
}
@Override public String getType() {
return this.getClass().getSimpleName();
}
}
public static class ActualObject2 extends ActualObject1<ActualObject2> {
Object data2;
@Override public void copyFrom(final ActualObject2 original) {
super.copyFrom(original);
this.data2 = original.data2;
}
}
基本上参数化class1,class2将自身指定为参数。一切正常,您可以创建两种类型的实例:
ActualObject1 obj1 = new ActualObject1();
然而,有一个“小”问题 - obj1有一个原始类型。完整的声明看起来很愚蠢:
ActualObject1<ActualObject1> obj2 = new ActualObject1<>();
但它有效。但是,此类的“原始类型”性质可以在此scanario中出现:
public static class SomeOtherParameterizedClass<T extends ISomeObject<T>> {
void copyObjects(T obj1, T obj2) {
obj1.copyFrom(obj2);
}
}
因此,您正在创建一些由&lt; T extends ISomeObject&lt; T&gt;&gt;参数化的随机类。理论上你可以这样说:&lt; T扩展ISomeObject&gt;但是你将无法安全地在“copyFrom”中使用T.换句话说 - 它是一个有效的类参数化,它有一个点。
但是你不能为ActualObject1参数化它:
SomeOtherParameterizedClass<ActualObject1> a1 = new SomeOtherParameterizedClass<>();
是的 - 不起作用。提示:
SomeOtherParameterizedClass<ActualObject2> a2 = new SomeOtherParameterizedClass<>();
工作得很好......
那么这里有什么正确的方法?我更感兴趣的是尽可能保持类型安全,因为你可以一直使用原始类型并且不用担心任何事情,但这是为了弱者! :-)
我们使用静态类型语言,所以这有点像学术问题 - 用泛型设计这个类层次结构的正确方法是什么?是偶尔使用实际需要的原始类型吗?