Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java嵌套自引用泛型_Java_Generics - Fatal编程技术网

Java嵌套自引用泛型

Java嵌套自引用泛型,java,generics,Java,Generics,我有一个类,它有一个自引用泛型参数和一个属于同一个超类的参数。静态函数与类具有相同的边界 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>

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

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(){
foo((T)null);
foo((C)null);//编译错误
}
静态无效foo(S_T T){
}
}
这会产生以下错误

绑定不匹配:类型为Bar的泛型方法foo(S_T)不匹配 适用于参数(C)。推断的类型C不是有效的 替换有界参数

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


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

我不是泛型高手,但我认为问题在于你声明foo()的类型为

void foo(S\T)
然后在两个不同的上下文中调用它,
foo()
需要不同的静态类型

在第一个上下文中,
S\u T
具有类型
T
,在第二个上下文中,它具有类型
C
。但是
T
C
被声明为
Bar
Bar
,它们是静态不兼容的类型。
我猜编译器在第一次调用中计算出了
foo()
的类型,然后正确地假设该类型在整个调用过程中必须保持不变,但事实并非如此。

简单的回答是,Java类型推断实际上非常蹩脚

Java没有对
Bar
声明中的通配符
执行任何智能推断,以推断它在逻辑上受
Bar<?,?>
(也不是说该边界中的
本身是有边界的,依此类推)。一旦你把
放在自己的位置上,Java就知道这些了。尽管没有什么能阻止你在
条的声明中把这个绑定放在通配符上,即使这对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) {
    }
}
public class Bar>>>void foo(S\u T T){
}
}

切换两个foo()调用的顺序仍然会在C行出现错误。好的,尝试更改类声明中C和T的顺序,即do BarI尝试了您建议的更改,错误更改为T,但我认为这只是因为它所做的只是重命名参数,而没有更改任何含义。我尝试了几种不同的方法对参数进行重新排序,错误仍然停留在带有通配符的参数上。此外,我认为虽然C和T彼此不兼容,但两者都应该与静态函数兼容,因为AFAIK的泛型参数基于每次调用时得到的输入;但从我从你的问题中收集到的信息来看,是类层次结构未能编译,而我的类层次结构编译了函数的参数约束,但失败了。是的,我开始怀疑java无法检测到通配符边界之间的连接。我开始尝试提供一个类:
Pie扩展了Bar
,而不是通配符。然后函数将
Bar
作为
foo
的参数类型有什么问题?关于
foo
中的
sut
您可以使用的唯一信息是,它是一个
。另外,这使得
foo
(至少在理论上)更加通用。该函数的通用参数是什么?你的意思是仅仅定义S_T和S_C而没有任何边界,因为参数中的Bar与Bar类的边界不匹配,这没有多大帮助。我突然想到,如果你想调用
foo((C)null)
,你也不关心
foo
Bar
的第二个参数,这意味着为什么不直接调用
静态void foo(S_t){}
?这是可行的,取决于你想做什么,因为你不能调用
newbar()
如果您使用通配符而不是S_C。
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) {
    }
}