2013-04-16 33 views
2

例子:误区类返回实例从Java中的子类的实例称为类的通用方法

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.5+,这对编译器来说不是秘密。 (解决)

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

这个问题在Java 1.7+中解决了吗?

+0

我不明白这个问题。但'S'和'SS'是这里的接口。 – midhunhk

+0

@silverback修改后的问题。接口有什么问题? –

回答

4

通过铸造到B您正在使用a raw type

使用原始类型从对象中删除所有通用信息,不管它在哪里。

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

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

改为铸造成B<? extends SS>

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

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

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

+0

我帮你。它是为了编译类的向后兼容性而制作的:可以使用带有过时代码和编译器的新版本的编译代码。 –

+0

问题更新 –

+0

关于问题更新的一些想法。这是一个修辞问题。我明白,直到我提出的编译器逻辑没有在1.5v编译器中实现(由标准定义),它将永远不会实现。至于我,投到'B <?扩展了SS>'破坏了代码的审美性,并且我一直倾向于编译类中的更多字节(由我提出的隐式方法)。 –

1

您没有参数化您的B实例。

比方说,你有实现SSC

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

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

+0

对不起,我犯了一个错误...我更新了问题。 –

+1

@Errandir问题依然存在:使用'(B)someInstanceOfB',您不参数化'B'。你必须至少使用'(B )someInstanceOfB'或者'(B )someInstanceOfB'('get'然后返回'Object')。 – sp00m

+0

你的论证有问题。代码块'S s =((B)someInstanceOfB).get()'和'S s =((A)someInstanceOfA).get()'可以正常工作。 –

相关问题