我有一个具有自引用泛型参数的类和一个具有相同超类的参数。静态函数与类具有相同的边界。
public class Bar<T extends Bar<T, C>, C extends Bar<C, ?>> {
Bar() {
foo((T) null);
foo((C) null);//compile error
}
static <S_T extends Bar<S_T, S_C>, S_C extends Bar<S_C, ?>> void foo(S_T t) {
}
}
这会产生以下错误。
绑定不匹配:Bar&lt; T,C&gt;类型的通用方法foo(S_T)。不是 适用于论点(C)。推断的类型C无效 替代有界参数&lt; S_T extends Bar&lt; S_T,S_C&gt;&gt;
我无法弄清楚为什么C
无法传递给foo()
,因为C
为Bar<C,?>
且通配符为Bar
,因为声明中的第二个参数表示它扩展了Bar。
我知道这可能是一个坏主意并产生难以理解的代码,但我真的想知道为什么这不能编译。
答案 0 :(得分:2)
简短的回答是Java类型推断实际上非常蹩脚。
Java未在?
声明中对通配符Bar
执行任何智能推断,以推断它在Bar< ?, ? >
的逻辑上受限(也不是?
s在那个界限本身是有界的,等等)。一旦你自己放了?
,这就是所有Java都知道的。虽然没有什么可以阻止你在Bar
的声明中将那个绑定放在通配符上,但是这对Java没有帮助; Java不会假设两个单独的?
引用相同的类型,即使更深入的分析意味着必须这样做。换句话说,即使使用以下代码,编译错误仍然存在:
public class Bar<T extends Bar<T, C>, C extends Bar<C, ? extends Bar<?, ? extends Bar<?, ?>>>> {
Bar() {
foo((T) null);
foo((C) null);//compile error
}
static <S_T extends Bar<S_T, S_C>, S_C extends Bar<S_C, ? extends Bar<?, ? extends Bar<?, ?>>>> void foo(S_T t) {
}
}
答案 1 :(得分:0)
我不是泛型的破解,但我认为问题是你声明foo()的类型是
<S_T extends Bar<S_T,S_C> > void foo(S_T)
然后在两个不同的上下文中调用它,这些上下文需要foo()
的不同静态类型。
在第一个上下文中,S_T
具有类型T
,而在第二个上下文中,它具有类型C
。但T
和C
被声明为Bar<T,?>
和Bar<C,?>
,它们是静态不兼容的类型。
我猜想编译器会在第一次调用中找出foo()
的类型,然后正确地假设,类型必须始终保持相同,而不是。