从Java中的子类实例调用的类的泛型方法对返回实例的类的误解

时间:2013-04-16 11:53:52

标签: java generics inheritance

示例:

interface S {}

interface SS extends S {}

abstract class A<T extends S> {
    T get() {…}
}

abstract class B<BT extends SS> extends A<BT> {}

为什么((B)someInstanceOfB).get()返回类型为S的对象(我们应该手动将其强制转换为SS),此时编译器可以确定返回的对象至少是SS类型1}}?

为什么编译器不使隐式类转换具有更清晰的代码?代码版本为1.5+,这对编译器来说并不是秘密。 (解决)

更新:为什么编译器不能编译B类,因为它隐式具有方法BT get() { return super.get(); }

Java 1.7 +中是否解决了这个问题?

2 个答案:

答案 0 :(得分:4)

通过转换为B,您正在使用a raw type

使用原始类型会从对象中删除所有通用信息,无论它在何处。

这意味着,对于原始类型Bget方法看起来像,它返回S(因为这是擦除(即实际类型)在运行时使用的类型参数T)。

为避免这种情况,绝不使用原始类型!它们专门用于向后兼容和与遗留代码的交互。

转而转向B<? extends SS>

不,这个问题可能永远不会在任何未来版本的Java中“解决”,因为当你正确使用泛型时它不存在。

关于更新:否,B 的方法BT get()。它有一个方法T get(),其中T绑定到类型参数BT,它具有下限SS。但是,由于在使用原始类型时会丢弃所有泛型类型信息,T仍然回退到原始擦除,即S

规则非常简单,基本上说“当你使用原始类型时,它就好像该类没有任何泛型”。然而,这种影响并不总是显而易见的,就像在这种情况下一样。

答案 1 :(得分:1)

您没有参数化B的实例。

假设您有C个实施SS的课程:

然后,new B<C>().get();将返回C类型的对象。

new B().get();行上,您的IDE必须告诉您“B是原始类型。应该参数化通用类型B的参考。”