2010-01-28 11 views
4

[更新]真实情况比我看起来最初的问题稍微复杂一些。 [/ UPDATE]当类型为通配符时如何将泛型结果用作泛型参数?

我有点被以下行为难住了。鉴于这样的代码:

interface Inter<T> { 
    T makeT(); 
    void useT(T t); 
} 

public class Foo { 
    public void bar(Qux q) { 
    Inter<?> x = getInterForQux(q); 
    x.useT(x.makeT()); 
    } 

    Inter<?> getInterForQux(Qux q) { 
    if(someTest(q)) { 
     return (Inter<Integer>) mkAnInterInt(); 
    } else { 
     return (Inter<Double>) mkAnInterDouble(); 
    } 
    } 
} 

javac的给我的错误:

useT(capture#478 of ?) in Inter<capture#478 of ?> cannot be applied to (java.lang.Object)

而Eclipse的给我:

The method useT(capture#1-of ?) in the type Inter<capture#1-of ?> is not applicable for the arguments (capture#2-of ?)

显然,不管是什么TmakeT()结果类型是与参数类型useT()相同。为什么我不能这样做?有没有解决方法?

回答

4

当您使用通配符时,编译器无法看到返回类型x.makeT()和参数类型x.useT()是相同的。为了保证他们都是一样的,你应该使用这里的泛型方法:

public class Foo { 
    public <T> void bar(Inter<T> x) { 
     x.useT(x.makeT()); 
    } 
} 
+0

实际情况并非如此琐碎这给你bar相同的签名,如上所述。首先,'bar'实际上是一种接口方法,所以我不能只在其上粘贴类型量词。但我认为你总是可以重构代码,通过将T的“范围”推入私有方法为量词腾出空间。 – 2010-01-28 22:33:37

1

这是合乎逻辑的,因为Inter<?>.makeT()可以返回任何东西,Inter<?>.useT(..)消耗任何东西,但两个anythings可以是不同的。

这将解决这个问题:

public <T> void bar(Inter<T> x) { 
    x.useT(x.makeT()); 
} 
+0

这完全不合逻辑:''x''只能有一个类型和一个类型变量。但你的建议是正确的。 – 2010-01-28 22:34:49

+0

它是 - 通用类型在运行时被擦除。 – Bozho 2010-01-28 22:44:22

+0

是的,显然编译器不能利用运行时不可用的任何东西。 – 2010-01-28 22:49:43

0

使用捕捉助手:

public void bar(Qux q) { 
    Inter<?> x = getInterForQux(q); 
    barPrivate(x); 
} 
private <T> void barPrivate(Inter<T> x) { 
    x.useT(x.makeT()); 
} 

,只要你想