Java 泛型嵌套在泛型中的类的泛型用法

Java 泛型嵌套在泛型中的类的泛型用法,java,generics,inner-classes,Java,Generics,Inner Classes,即使这不是一个好的练习,我也想知道为什么 下面的代码没有编译,我真的不明白为什么 假设我对小丑、王后和国王有一个抽象的定义: abstract class JokerA { //JokerA does things } abstract class QueenA<J extends JokerA> { //QueenA makes use of J class Princess { void receiveGift(Gift gift) {

即使这不是一个好的练习,我也想知道为什么

下面的代码没有编译,我真的不明白为什么


假设我对小丑、王后和国王有一个抽象的定义:

abstract class JokerA {
    //JokerA does things
}

abstract class QueenA<J extends JokerA> {
    //QueenA makes use of J
    class Princess {
        void receiveGift(Gift gift) {
            /* ... */
        }
    }
}

abstract class KingA<Q extends QueenA<?>> {
    KingA(Q.Princess princess) {
        Gift giftForPrincess = new Gift();
        princess.receiveGift(giftForPrincess);
    }
}
抽象类{
//乔凯拉做事
}
抽象类皇后{
//奎纳利用J
公主班{
无效接受礼品(礼品){
/* ... */
}
}
}
抽象类KingA>扩展了KingA{
金B(Q.公主){
超级(公主);//错误
}
}
错误是:


KingA(QueenA首先,这里只有一个类名为
Princess
,它是
QueenA.Princess
。没有
QueenB.Princess
——如果您编写
QueenB.Princess
,编译器只会理解它的意思是
QueenA.Princess
。请注意,
Princess
QueenA
,一个泛型类,
QueenA.Princess
也是一个泛型类(由
QueenA
的参数参数化)。当它被参数化时,它看起来像
QueenA.Princess

由于问题是类
Princess
的两个值之间的兼容性,并且我们在上面提到了一个这样的类,因此唯一的兼容性问题是泛型类型参数。传递到
super()的类型
被认为是
Q.Princess
。但正如我们前面提到的,
Princess
属于
QueenA
,而不是
QueenB
Q
。因此编译器在编译时会自动将其重新写入
QueenA.Princess
。问题是什么是
东西
。基本上,问题是
Q
是一个
QueenA
Q
是一个绑定了
QueenB
的类型变量。这意味着可以使用
Q
作为
QueenB
X
作为满足
QueenB
类型参数边界的任何类型的类(即扩展
JokerB
)因此,我们不能假设关于
X
的任何东西,除了它是
JokerB
QueenB
的子类型,它扩展了
QueenA
,这意味着
Q
QueenA
只是编译器打印出来表示未知类型的东西。因此,在这一点上,编译器已经发现
Q.Pr乱伦真正的意思是皇后公主

然后将其传递给
super()
,它是
KingA
的构造函数。此类型参数的参数类型也被写入
Q.Princess
(注意:这是
KingA
Q
,一个不同类型的参数;请不要混淆)。如果您按照上面相同的分析进行操作,您将看到编译器看到这个
Q.Princess
实际上意味着
QueenA.Princess

问题是,
QueenA.Princess
QueenA.Princess
的一个子类型吗?即
第一个未知子类型
是否与
第二个未知子类型
相同?(请记住泛型是不变的。)编译器只看这一点就会说,它不知道它们是否相同,因为两个未知类型肯定会不同,所以它们不兼容

你可能会说,等一下,你知道
Q
是一个
QueenA
对于某个未知类型
X
KingB
被声明为扩展
KingA
,因此
KingB
中的
Q
对于特定对象的作用域与
KingB
中的
Q
的作用域相同是相同的,未知的
X
在这两种情况下都是相同的。但这不适用于这里,因为不再考虑
Q
。请记住,没有类型
Q.Princess
。它所指的真正类型是
QueenA.Princess
QueenA.Princess
是在编译时计算出来的每个类的每个构造函数。一旦算出它是
未知类型
,它就被固定为
未知类型
,并且与类的类型参数
Q
无关。因此这两个未知类型没有关系

您可以通过使用新的类型参数来解决此问题,而不是让编译器推断未知类型。然后,类型参数可以允许您连接该类型的不同用途,让编译器知道它们是同一类型。类似于以下内容:

abstract class KingA<J extends JokerA, Q extends QueenA<J>> {
    KingA(Q.Princess princess) {
        Gift giftForPrincess = new Gift();
        princess.receiveGift(giftForPrincess);
    }
}

abstract class KingB<J extends JokerB, Q extends QueenB<J>> extends KingA<J, Q> {
    KingB(Q.Princess princess) {
        super(princess);
    }
}
抽象类KingA{
金卡(问公主){
礼品礼品Forprincess=新礼品();
公主。接受礼物(礼物或礼物);
}
}
抽象类KingB扩展了KingA{
金B(Q.公主){
超级(公主);
}
}
KingA(QueenA<capture<?>>.Princess) in KingA cannot be applied to (Q.Princess)
abstract class KingA<J extends JokerA, Q extends QueenA<J>> {
    KingA(Q.Princess princess) {
        Gift giftForPrincess = new Gift();
        princess.receiveGift(giftForPrincess);
    }
}

abstract class KingB<J extends JokerB, Q extends QueenB<J>> extends KingA<J, Q> {
    KingB(Q.Princess princess) {
        super(princess);
    }
}