【问题标题】:Why won't this code with Java generics compile?为什么这个带有 Java 泛型的代码不能编译?
【发布时间】:2021-10-28 05:23:52
【问题描述】:

考虑以下代码:

import java.math.BigDecimal;

class Scratch {

  public static class Test<N extends Number> {

    public void foo(Class<N> numberClass) {
      System.out.println(numberClass);
    }

    public void bar() {
      foo(BigDecimal.class);
    }
  }

  public static void main(String[] args)  {
    Test<Number> t = new Test<>();
    t.bar();
  }
}

这无法在第 12 行(对 foo() 的调用)与 incompatible types: java.lang.Class&lt;java.math.BigDecimal&gt; cannot be converted to java.lang.Class&lt;N&gt; 进行编译。我不明白,因为通用N 扩展了Number,所以我应该能够将BigDecimal.class 传递给采用Class&lt;N&gt; 参数的方法。 TIA 有什么想法!

【问题讨论】:

  • Class&lt;? extends Number&gt; 表示Number 的任何子类。 Class&lt;N&gt; 表示Number特定 类型,用N 表示,在Test 内部是不可知的,因为type erasure
  • Java 在这件事上有点落后。

标签: java generics


【解决方案1】:

假设调用者做了:

var t = new Test<Integer>();
t.bar();

那么,bar() 会将BigDecimal 传递给foo(),它需要Integer

【讨论】:

    【解决方案2】:

    简短的回答确实是BigDecimal 不一定是N。这有点令人困惑,因为BigDecimal&lt;N extends Number&gt; 范围内,但当前实例的泛型类型参数可以是扩展Number 的任何类型,但bar 方法假定BigDecimal

    检查这个稍微修改过的方法:

    public void bar() {
        new Test<BigDecimal>().foo(BigDecimal.class);
    }
    

    该方法编译。为什么?因为Test&lt;BigDecimal&gt;()BigDecimal 作为类型参数。

    当您调用foo(BigDecimal.class) 时,您假设 this 被实例化为BigDecimal 作为类型参数,这并不总是正确的,并且编译器正在防止错误。


    您的代码中的错误类似于ArrayList&lt;T&gt; 中的假设bar() 方法,该方法执行add("string"),出于同样的原因,这将是错误的(可能创建实际的数组列表实例来保存整数,而不是字符串,所以内部代码不应该做出假设)

    【讨论】:

      猜你喜欢
      • 2020-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-26
      • 2012-07-06
      相关资源
      最近更新 更多