Java嵌套自引用泛型

Java nested self referential generic

我有一个类,它有一个自引用的泛型参数和一个属于同一个超类的参数。静态函数与类具有相同的边界。

1
2
3
4
5
6
7
8
9
10
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) {
    }
}

这会产生以下错误。

Bound mismatch: The generic method foo(S_T) of type Bar is not
applicable for the arguments (C). The inferred type C is not a valid
substitute for the bounded parameter >

我不明白为什么C不能传入foo(),因为CBar,通配符是Bar,因为声明中的第二个参数表示它扩展了条。

我知道这可能是一个坏主意,并产生了难以理解的代码,但我真的想知道为什么这不能编译。


简短的答案是Java类型的推理实际上是相当蹩脚的。

在EDCOX1(10)的声明中,Java没有对通配符EDOCX1 9进行任何智能推理,以推断它在逻辑上是由EDCOX1〔11〕限制的(也不意味着EDCOX1在该约束中的9个S本身是有界的,等等)。一旦你把EDOCX1,9本身,这就是所有的Java知道。尽管没有任何东西阻止您在EDCOX1(10)中声明通配符,即使这样对Java也没有帮助;Java不会假设两个单独的EDCOX1×9个s指的是同一类型,即使更深的分析暗示它们必须是相同类型的。换句话说,即使使用以下代码,编译错误仍然存在:

1
2
3
4
5
6
7
8
9
10
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) {
    }
}


对于泛型,我不是一个裂缝,但我认为问题在于您将foo()的类型声明为

1
<S_T extends Bar<S_T,S_C> > void foo(S_T)

然后在两个不同的上下文中调用它,这些上下文要求foo()使用不同的静态类型。

在第一个上下文中,S_T具有T类型,在第二个上下文中,它具有C类型。但是,TC被声明为BarBar,它们是静态上不相容的类型。我想编译器会在第一次调用中找出foo()的类型,然后正确地假定该类型在整个过程中必须保持不变,而事实并非如此。