【问题标题】:Why compiler cannot infer generic types of the inner class in Java?为什么编译器无法推断 Java 内部类的泛型类型?
【发布时间】:2021-05-28 12:05:05
【问题描述】:
class A<T>
{
    class InnerA<U>
    {}
}

public class Main
{
    public static void main(String[] args)
    {
        A<Integer>.InnerA<String> var = new A<>().new InnerA<>();
    }
}

当上面的代码 sn-p 被编译时,它会导致编译时错误说“不兼容的类型:无法推断 A.InnerA&lt;&gt; 的类型参数。在我看来,编译器应该能够推断出类型是InnerA&lt;String&gt;.

为什么它不能这样做?如果有人能解释它是如何在幕后工作的,那将会很有帮助。

【问题讨论】:

  • 这是 JAVA / JVM AFAIR 的限制:无法连续干扰两个泛型类型。您需要明确设置右侧的类型

标签: java generics language-lawyer type-inference inner-classes


【解决方案1】:

编译器错误信息具有误导性。

编译器只能从赋值左侧推断出表达式的类型,前提是该表达式的结果是实际赋值的。在您的示例中,new A&lt;&gt;() 未分配,而仅用于内部类的合格实例化¹。由于new A&lt;&gt;() 没有赋值上下文,编译器推断new A&lt;Object&gt;()

对于.new InnerA&lt;&gt;(),有一个赋值上下文,编译器尝试使用赋值的左侧推断结果类型,但由于A 的类型已经不兼容而失败。在缩短的编译器消息中,无法推断 InnerA 的类型是可见的,但不是 A 的类型参数不匹配的原因。

长错误信息看起来像

Main.java:11: error: incompatible types: cannot infer type arguments for A.InnerA<>
        A<Integer>.InnerA<String> var = new A<>().new InnerA<>();
                                                            ^
  reason: no instance(s) of type variable(s) U exist
          so that A<Object>.InnerA<U> conforms to A<Integer>.InnerA<String>

  where U is a type-variable:
    U extends Object declared in class A.InnerA

所以问题仍然被报告为“找不到U的类型”,但我们也可以看到更深层次的原因是没有U可以解决问题A&lt;T&gt; 的类型不匹配。

我们也可以通过换行来演示实际原因

A<Integer>.InnerA<String> var = new A<>().new InnerA<String>();

InnerA 提供正确的类型,现在得到

incompatible types:
    A<Object>.InnerA<String> cannot be converted to A<Integer>.InnerA<String>

或将行改为

A<Integer>.InnerA<String> var = new A<Integer>().new InnerA<>();

这将解决问题,因为现在A 具有正确的类型,并且可以从左侧推断出InnerA 的类型。


¹如果您有genericMethod1().method2(),则会出现同样的问题

【讨论】:

  • 大部分我都能理解,但是由于没有new A&lt;&gt;() 的赋值上下文,编译器推断new A&lt;Object&gt;()。为什么在A&lt;Integer&gt; var = new A&lt;&gt;();的情况下不会发生?
  • @ArvindKumarAvinash 因为那时你有一个分配上下文。正如脚注中所暗示的,当您拥有像 Type var = expr1 [.expr2] [.expr3] .lastExpression; 这样的链时,总会出现问题。左侧Type 将仅用于lastExpression 的推断。所以对于所有前面的表达式,只会使用它们的独立类型。这意味着当类型参数没有其他约束时推断Object。当右侧没有链时,类型推断将始终适用于整个表达式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-22
  • 2019-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多