java - 返回类型中的推断通配符泛型

标签 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 提供):

Type mismatch: cannot convert from TestClass.Pair<Class<capture#1-of ?>,String> to TestClass.Pair<Class<?>,String>

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

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

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

疯狂猜测:“捕获#1-of ?”不知何故似乎暗示通配符是由编译器即时填充的,使类型成为 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);
    }
}

最佳答案

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

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

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

这里的问题(如您所建议的)是编译器正在执行 capture conversion .我相信这是 [§15.12.2.6 of the JLS] 的结果:

  • The result type of the chosen method is determined as follows:
    • If the method being invoked is declared with a return type of void, then the result is void.
    • Otherwise, if unchecked conversion was necessary for the method to be applicable then the result type is the erasure (§4.6) of the method's declared return type.
    • Otherwise, if the method being invoked is generic, then for 1in, let Fi be the formal type parameters of the method, let Ai be the actual type arguments inferred for the method invocation, and let R be the declared return type of the method being invoked. The result type is obtained by applying capture conversion (§5.1.10) to R[F1 := A1, ..., Fn := An].
    • Otherwise, the result type is obtained by applying capture conversion (§5.1.10) to the type given in the method declaration.

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

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

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

关于java - 返回类型中的推断通配符泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1294227/

相关文章:

java - 使用 RadioGroup 和 RadioButtons

java.util.Comparator.naturalOrder 采用 <T extends Comparable<? super T>> 并返回一个 Comparator<T> - 为什么?

java - 提供外部 Tomcat 时的 Spring Boot REST Web 服务端点

java - 哪个相当于 javaFX 中的 JLayeredPane?

generics - Kotlin无法通过方法引用推断Function的类型

java - 正确分配泛型变量

java - 泛型方法中的泛型类

java - Bounded Type parameter (T extends) 和 Upper Bound Wildcard (? extends) 的区别

java - 什么是 PECS(生产者扩展消费者 super )?

java - 使用 gradle 3.0.0-alpha2 时 Android Studio 3.0 Canary 2 : Failed to apply plugin,