【发布时间】: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<Baz> col = Test.<Foo, Baz>unsafe(new Foo ()); -
这一切都归结为 Foo 是一个 Object,但 Tag
不是 Tag -
@cppbeginner 我不同意。问题不在于 Tag
不起作用。这就是它应该的方式,您的链接问题如何表明 Test.unsafe 不应该引发编译器错误。 -
@matt 它没有 - 链接的问题解释了为什么第一个 safe() 示例确实给出了编译器错误(unsafe() 示例的推断类型 Object 不适用于安全() 示例由于缺乏协方差)。如果将 Col
和 Tag 替换为数组类型 V[] 和 T[],则 safe() 示例编译 - 这是因为数组是协变的。 -
在不安全的情况下,为什么不使用 T 作为上限?
标签: java generics type-inference type-erasure