【问题标题】:Generic Method Type Argument Inference Issue通用方法类型参数推理问题
【发布时间】:2021-09-13 06:42:40
【问题描述】:

我无法理解为什么下面的第二次调用会产生编译器错误。为什么不能像第一次调用那样将 Number 推断为类型参数?

typeArgInference(new Integer[100], new ArrayList<Number>()); // Infers Number

typeArgInference(new Number[100], new ArrayList<Integer>()); // compiler error

<T> void typeArgInference(T[] a, Collection<T> c) {}

可能是我在这里遗漏了一些东西。如果 JLS 对此行为有任何规定,请务必附上链接。

【问题讨论】:

  • 您是否意识到Collection&lt;Integer&gt; 不能隐式转换为Collection&lt;Number&gt;
  • 错误是什么?
  • 类型参数推断可能导致不变性这一事实并没有引起我的注意。一直在研究仅涉及非泛型方法的不变性示例。谢谢。

标签: java generics type-inference


【解决方案1】:

泛型是不变的,数组是协变的:

  • Integer[] 可以充当Number[](因为IntegerNumber 的子类)
  • ArrayList&lt;Integer&gt; 不能充当ArrayList&lt;Number&gt;(因为您可以将Double 添加到后者,但您不能将Double 添加到Integers 的列表中)。

当然,您可以尝试将Double 放入Number[],但如果您的Number[] 真的是Integer[],则ArrayStoreException 会失败。这将是运行时故障。

在语言支持泛型之前,使数组具有协变是一种软糖。人们意识到这是一个问题(因为运行时失败很糟糕),因此为什么泛型被设计成不变的。

既然您要求提供 JLS 链接:


如果您向列表类型添加上限,您的两个示例都将编译:

<T> void typeArgInference(T[] a, Collection<? extends T> c) {}

在这两种情况下,Number 都是满足类型约束的类型:

  • Integer[] 可以充当Number[]ArrayList&lt;Number&gt;Collection&lt;Number&gt;,这是 Collection&lt;? extends Number&gt;
  • Number[] 可以充当Number[](显然); ArrayList&lt;Integer&gt;Collection&lt;Integer&gt;,这是 Collection&lt;? extends Number&gt;

您不能在该方法中向Collection 添加任何内容(除了文字null;或通过原始类型破坏类型安全)。

【讨论】:

    猜你喜欢
    • 2011-04-07
    • 1970-01-01
    • 2011-11-07
    • 2021-04-06
    • 1970-01-01
    • 2023-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多