嵌套在泛型中的类的泛型使用

时间:2016-12-13 14:27:42

标签: 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 KingA<Q extends QueenA<?>> {
    KingA(Q.Princess princess) {
        Gift giftForPrincess = new Gift();
        princess.receiveGift(giftForPrincess);
    }
}

这很好用。 但是,我也想要定义一个更专业但仍然抽象的小丑,女王和国王

abstract class JokerB extends JokerA {
    //JokerB does some things differently
}

abstract class QueenB<J extends JokerB> extends QueenA<J> {
    //QueenB makes use of J sometimes differently, because she knows how JokerBs behave
}

abstract class KingB<Q extends QueenB<?>> extends KingA<Q> {
    KingB(Q.Princess princess) {
        super(princess); //error
    }
}

错误是:

KingA(QueenA<capture<?>>.Princess) in KingA cannot be applied to (Q.Princess)

但是,我看不出公主课是如何与众不同的。

任何人都可以启发我吗?

1 个答案:

答案 0 :(得分:1)

首先,这里只有一个名为Princess的班级,即QueenA.Princess。没有QueenB.Princess - 如果您编写QueenB.Princess,编译器只会将其理解为QueenA.Princess。请注意,由于PrincessQueenA的非静态内部类,因此泛型类QueenA.Princess也是泛型类(由QueenA的参数参数化)。在参数化时,它看起来像QueenA<something>.Princess

由于问题是类Princess的两个值之间的兼容性,并且我们在上面提到过有一个这样的类,唯一的兼容性问题是泛型类型参数。传递给super()的类型应该是Q.Princess。但正如我们上面提到的,Princess属于QueenA,而不是QueenBQ。因此,编译时编译器会自动将其重写为QueenA<something>.Princess。问题是something是什么。基本上,问题是QQueenA<what>Q是一个带有绑定QueenB<?>的类型变量。这意味着有人可以使用此类,QQueenB<X>X为满足QueenB类型参数边界的任何类型(即扩展{{1}的类型}})。因此,除了JokerB的子类型之外,我们不能假设XJokerB扩展QueenB<X>,这意味着QueenA<X>QQueenA<X>只是编译器打印以表示未知类型的内容。所以在这一点上,编译器已经发现<capture ...>实际上意味着Q.Princess

然后将其传递给QueenA<some unknown type that extends JokerB>.Princesssuper()的构造函数。此类型参数的参数类型也写为KingA(注意:这是Q.Princess的{​​{1}},一个不同的类型参数;不要混淆)。如果您按照上述相同的分析,您将看到编译器发现此KingA实际上意味着Q

问题是,Q.Princess的子类型是QueenA<some unknown type that extends JokerA>.Princess吗?即QueenA<first unknown subtype>.PrincessQueenA<second unknown subtype>.Princess相同? (记住泛型是不变的。)编译器只是看着它会说它不知道它们是否相同,因为两种未知类型当然可能不同,所以它们不兼容。

你可能会说,等一下,你知道first unknown subtype对于某种未知类型second unknown subtypeQQueenA<X>被宣布延长X ,因此特定对象的KingB<Q>范围中的KingA<Q>Q范围内的KingB相同。所以Q是相同的,未知的KingB在两种情况下都是相同的。但这不适用于此,因为Q不再被考虑了。请记住,没有类型X。它的实际类型是Q。在编译每个类的每个构造函数时,在编译时计算出Q.Princess。一旦它被认为是QueenA<something>.Princess,它就会固定为QueenA<something>.Princess,并且与作为类的类型参数的unknown type无关。所以两种未知类型没有关系。

您可以使用新的类型参数来解决它,而不是让编译器推断出未知类型。然后,type参数可以允许您连接类型的单独使用,以使编译器知道它们是相同的类型。像这样:

unknown type