2009-08-18 128 views
16

Java通常可以基于参数(甚至在返回类型上,与例如C#相比)推断泛型。返回类型推断的通配符泛型

个例子:我有一个泛型类Pair<T1, T2>这只是存储的一对值,可以通过以下方式使用:

Pair<String, String> pair = Pair.of("Hello", "World"); 

的方法of看起来就像这样:

public static <T1, T2> Pair<T1, T2> of(T1 first, T2 second) { 
    return new Pair<T1, T2>(first, second); 
} 

非常好。但是,这已不再适用于以下用例,这需要通配符:(注意显式类型转换,使List.class正确的类型)

Pair<Class<?>, String> pair = Pair.of((Class<?>) List.class, "hello"); 

代码失败,出现以下错误(提供通过Eclipse中):

类型不匹配:不能从TestClass.Pair<Class<capture#1-of ?>,String>转换为TestClass.Pair<Class<?>,String>

然而,显式调用构造函数仍然按预期工作:

Pair<Class<?>, String> pair = 
    new Pair<Class<?>, String>((Class<?>) List.class, "hello"); 

有人能解释这种现象?它是否由设计?是想要?我做错了什么,或者我偶然发现了编译器中的设计/错误?

胡乱猜测:“捕获#1-的?”不知何故似乎暗示通配符由上飞编译器填充,使得类型Class<List>,因而失败的转换(从Pair<Class<?>, String>Pair<Class<List>, String>) 。这是正确的吗?有没有办法解决这个问题?


为了完整起见,这里是Pair类的简化版本:

public final class Pair<T1, T2> { 
    public final T1 first; 
    public final T2 second; 

    public Pair(T1 first, T2 second) { 
     this.first = first; 
     this.second = second; 
    } 

    public static <T1, T2> Pair<T1, T2> of(T1 first, T2 second) { 
     return new Pair<T1, T2>(first, second); 
    } 
} 
+0

看起来转换器看到“of”的签名,因为它返回一个Pair <?扩展类,?扩展类>类型。 对于最终的类,它似乎足够聪明,减少了扩展部分,这就是为什么它不会在字符串上投诉。 – Zed 2009-08-18 15:08:43

+0

嗯,有趣。感谢您在此链接我。 – jjnguy 2011-06-13 19:14:30

+0

它现在在java8中工作。目标类型也被咨询为inferene。 – ZhongYu 2015-08-06 17:25:21

回答

13

构造成功运作的原因是,你明确指定类型参数。

Pair<Class<?>, String> pair = Pair.<Class<?>, String>of(List.class, "hello"); 

当然,整个的原因,你必须摆在首位的静态方法可能只是为了让类型推断(不带处工作的构造函数:静态方法,如果你这样做也将工作所有)。

这里的问题(如你所建议的)是编译器执行capture conversion。相信这是由于 [§15.12.2.6 of the JLS]结果:

  • 所选方法的结果类型被确定如下:
    • 如果被调用的方法被声明用的空隙, 返回类型那么结果是无效的。
    • 否则,如果未选中转换对于 方法适用是必要的,那么 结果类型是该方法的声明返回类型的删除(第4.6节) 。
    • 否则,如果被调用的方法是通用的,那么对于1英寸,让 网络连接是 形式类型参数的方法中,让艾是实际的类型推断方法 调用 参数,令R为所述声明 返回类型的方法是 调用。通过将捕获转换 (§5.1.10)应用于R [F1:= A1,...,Fn:= An],获得结果类型 。
    • 否则,通过在方法声明中将捕获 转换(第5.1.10节)应用于 类型获得结果类型。

如果你真的想要的推论,一个可能的解决办法是做这样的事情:

Pair<? extends Class<?>, String> pair = Pair.of(List.class, "hello"); 

变量pair将有更广阔的类型,它也意味着位更多地输入变量的类型名称,但至少不需要再投入方法调用。

+0

非常感谢。我仍在考虑解决方案是否使核心更加混乱。目前,我会保持原样。 – 2009-08-18 15:22:15