Java Generics:警告需要未经检查的强制转换以符合<interfacename> </interfacename>

时间:2009-07-24 17:09:49

标签: java generics

我有一个界面

interface x {
    A getValue();
}

和实施

class y implements x {
    public B getValue() { return new B();}
}

B是A的子类。我猜这是因为协变覆盖。

但如果我将界面重写为

interface x{
    <T extends A> T getValue();
}

我在实施中收到警告

  

警告需要未经检查的强制转换   符合A.getValue()

2个版本的界面有什么区别?我以为他们是一样的。

4 个答案:

答案 0 :(得分:4)

界面的第二个版本是错误的。它表示getValue将返回您要求的任何子类 - 返回类型将根据左侧的表达式推断。

因此,如果您获得对x的引用(让我们称之为obj),您可以在没有编译器警告的情况下合法地进行以下调用:

x obj = ...;
B b = obj.getValue();

在您的示例中可能不正确,因为如果您添加另一个同时扩展C的班级A,您也可以合法地拨打电话:

C c = obj.getValue();

这是因为T不是属于接口的类型变量,只是属于方法本身。

答案 1 :(得分:3)

基本上当你在做一个<T extends A>时,你说你想要一个特定的A子类,而不是任何A,因为那样你就可以这样做:

 A getValue();

编译器警告您它无法确保返回A的特定定义子类,只返回A本身。

编辑:为了更好地解释这一点,B是A的子类,但不一定是A的唯一子类。请考虑以下层次结构。

B延伸A. C扩展A而不是B

现在我有一个方法:

public void someMethod(x value) {
    C c = x.getValue();
}

遵循泛型,这应该编译并保证没有运行时类强制转换异常(这里的接口可能存在其他问题,但肯定有可能用于正确演示这种情况的情况 - 我保持你的例子)。 / p>

但是如果你将y的实例传递给这个方法怎么办?

好吧,现在我得到的是B而不是C.编译器警告你可能会发生这种情况。

答案 2 :(得分:1)

编译器告诉你的是没有办法解决泛型。除了作为输出之外,T没有在任何地方定义 - 你在谈论哪个T?如果接口被广泛化为类型T:

interface x <T extends A> {
    T getValue()
}

然后这会起作用,或者如果方法采用了一个值来定义你想要的返回类型:

interface x {
    <T extends A> T getValue(T someArgument)
}

interface x {
    <T extends A> T getValue(Class<T> someArgument)
}

然后就没有警告了。

编辑:请参阅waxwing的帖子,了解为什么不应该使用泛型来解决这个特定问题。我只是展示了泛型是否合适。

答案 3 :(得分:0)

所以,基于AlbertoPL和Yishai的两个答案,试试这个:

class y implements x {
    A getValue(){ return new B();}
}

B延伸A,所以没关系。调用者不需要知道返回A的子类,只是它扩展了A.所以我们去了:)