返回类型的推断通配符泛型

时间:2009-08-18 14:24:48

标签: java generics bounded-wildcard

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);
}

非常好。但是,这不再适用于以下需要使用通配符的用例:

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

(注意显式转换以使List.class成为正确的类型。)

代码失败并出现以下错误(由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-of?”似乎暗示通配符由动态编译器填充,使类型为Class<List>,从而导致转换失败(来自{ {1}}到Pair<Class<?>, String>)。这是正确的吗?有办法解决这个问题吗?


为了完整起见,这里是Pair<Class<List>, String>类的简化版本:

Pair

1 个答案:

答案 0 :(得分:13)

构造函数的工作原理是您明确指定了类型参数。如果你这样做,静态方法也会起作用:

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

当然,首先你有静态方法的全部原因可能只是获取类型推断(根本不适用于构造函数)。

这里的问题(正如你的建议)是编译器正在执行capture conversion。我相信这是 [§15.12.2.6 of the JLS]

的结果
  
      
  • 所选方法的结果类型确定如下:      
        
    • 如果声明被调用的方法的返回类型为void,   结果是无效的。
    •   
    • 否则,如果需要未经检查的转换   然后适用的方法   结果类型是擦除(§4.6)   方法的声明返回类型。
    •   
    • 否则,如果被调用的方法是通用的,那么对于1in,让   Fi是正式的类型参数   方法,让艾是实际的类型   推断该方法的参数   调用,让R成为声明的   返回类型的方法   调用。获得结果类型   通过应用捕获转换   (§5.1.10)到R [F1:= A1,...,Fn:=   的]。
    •   
    • 否则,通过应用捕获获得结果类型   转换(§5.1.10)到给定的类型   在方法声明中。
    •   
  •   

如果你真的想要推理,一种可能的解决方法是做这样的事情:

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

变量pair将具有更宽的类型,并且它确实意味着在变量的类型名称中输入更多内容,但至少您不再需要在方法调用中进行转换。