【问题标题】:Inferred wildcard generics in return type返回类型中推断的通配符泛型
【发布时间】:2009-08-18 14:24:47
【问题描述】:

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&lt;Class&lt;capture#1-of ?&gt;,String&gt; 转换为 TestClass.Pair&lt;Class&lt;?&gt;,String&gt;

但是,显式调用构造函数仍然可以按预期工作:

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

有人可以解释这种行为吗?是设计使然吗? 需要吗?我是做错了什么,还是偶然发现了编译器中的设计缺陷/错误?

大胆猜测:“capture#1-of ?”不知何故似乎暗示通配符是由编译器动态填充的,使类型为Class&lt;List&gt;,因此转换失败(从Pair&lt;Class&lt;?&gt;, String&gt;Pair&lt;Class&lt;List&gt;, String&gt;)。这是正确的吗?有没有办法解决这个问题?


为了完整起见,这里是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);
    }
}

【问题讨论】:

  • 看起来转换器在返回 Pair 时看到了“of”的签名,?扩展类> 类型。对于最终类,它似乎足够聪明,可以减少扩展部分,这就是它不会抱怨字符串的原因。
  • 嗯,很有趣。感谢您在此处链接我。
  • 它现在可以在 java8 中使用。推理的目标类型也被咨询。

标签: java generics bounded-wildcard


【解决方案1】:

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

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 是的形式类型参数 方法,设 Ai 为实际类型 为方法推断的参数 调用,并令 R 为声明的 方法的返回类型是 调用。得到结果类型 通过应用捕获转换 (§5.1.10) 到 R[F1 := A1, ..., Fn := 一个]。
    • 否则,通过应用捕获获得结果类型 转换(§5.1.10)到给定的类型 在方法声明中。

如果您真的想要推理,一种可能的解决方法是执行以下操作:

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

变量pair 将具有更广泛的类型,这确实意味着要输入更多变量的类型名称,但至少您不再需要在方法调用中进行强制转换。

【讨论】:

  • 非常感谢。我仍在考虑解决方法是否不会使核心更加混乱。目前,我将保持原样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-11
  • 2020-03-23
  • 2016-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多