【问题标题】:Java generic method: inconsistency when inferring upper bound on return type from argument typeJava泛型方法:从参数类型推断返回类型的上限时不一致
【发布时间】:2018-09-02 07:19:15
【问题描述】:

考虑以下几点:

class Col<T> { }
class Tag<T> { }
class Foo { }
class Bar { }
class Baz extends Bar { }
class Test {
   static <T, V extends T> Col<V> safe (Tag<T> t) { return null; }
   static <T, V extends T> Col<V> unsafe (T t) { return null; }
}

那么这将产生一个期望的编译时错误(因为 Baz 没有扩展 Foo):

Col<Baz> col = Test.safe (new Tag<Foo> ());

但这不会:

Col<Baz> col = Test.unsafe (new Foo ());

作为参考,它按预期编译(因为 Baz 扩展了 Bar):

Col<Baz> col = Test.safe (new Tag<Bar> ());

为什么编译器 (Java 8) 在“安全”情况下可以推断并使用 T 作为返回类型参数的上限,但在“不安全”情况下却不能?

我想我理解为什么它在“不安全”情况下不起作用,因为 T 被 Object 擦除,但可能有点惊讶它在“安全”情况下起作用。至少我觉得它是不一致的。

【问题讨论】:

  • 将 T 推断为 Object 似乎很奇怪,因为这几乎正是您要使用泛型的原因。如果你是明确的,它将不起作用:Col&lt;Baz&gt; col = Test.&lt;Foo, Baz&gt;unsafe(new Foo ());
  • 这一切都归结为 Foo 是一个 Object,但 Tag 不是 Tag。请参阅此相关问题。 stackoverflow.com/q/2745265/6253321
  • @cppbeginner 我不同意。问题不在于 Tag 不起作用。这就是它应该的方式,您的链接问题如何表明 Test.unsafe 不应该引发编译器错误。
  • @matt 它没有 - 链接的问题解释了为什么第一个 safe() 示例确实给出了编译器错误(unsafe() 示例的推断类型 Object 不适用于安全() 示例由于缺乏协方差)。如果将 Col 和 Tag 替换为数组类型 V[] 和 T[],则 safe() 示例编译 - 这是因为数组是协变的。
  • 在不安全的情况下,为什么不使用 T 作为上限?

标签: java generics type-inference type-erasure


【解决方案1】:
Col<Baz> col = Test.unsafe (new Foo ());

Test.unsafe 在这种情况下将T 推断为Object;因为一切都扩展了Object,所以边界是满足的。

Col<Baz> col = Test.safe (new Tag<Foo> ());

T 在这种情况下不能被推断为Object:它是Foo,因为你说过它是Foo,没有任何界限。同样,V 正好是 Baz。由于Baz 没有扩展Foo,这是一个编译器错误。

【讨论】:

  • 谢谢,这个答案以及@cpp 初学者关于 Tag 不能分配给 Tag 的澄清说明了这一点。总结一下:在“usafe”的情况下,可以将 T 替换为使代码在左侧使用 Baz 编译,在右侧使用 Foo 编译的类型。在相应的“安全”情况下,没有可以替换 T 的类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-23
  • 1970-01-01
  • 1970-01-01
  • 2012-02-20
  • 2021-06-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多