所以,假设我们有一个简单的界面
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);
}
}
因此,您正在创建一些由 <T extends ISomeObject<T>> 参数化的随机类。理论上你可以这样说:<T extends ISomeObject> 但是你不能安全地在“copyFrom”中使用 T。换句话说 - 这是一个有效的类参数化,它有一点。
但是你不能为 ActualObject1 参数化它:
SomeOtherParameterizedClass<ActualObject1> a1 = new SomeOtherParameterizedClass<>();
是的 - 不起作用。暗示:
SomeOtherParameterizedClass<ActualObject2> a2 = new SomeOtherParameterizedClass<>();
工作得很好...
那么这里的正确方法是什么?我对尽可能地保留类型安全更感兴趣,因为可以肯定你可以一直使用原始类型而不必担心任何事情,但它是为弱者准备的!:-)
我们使用的是静态类型语言,所以这有点像一个学术问题——用泛型设计这个类层次结构的正确方法是什么?是否偶尔需要使用原始类型才能正常工作?