即使不是很好的做法,我也想知道原因。
下面的代码无法编译,我也不知道为什么。
假设我有一个小丑,皇后和国王的抽象定义:
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)
但是,我看不出公主课会是什么样的人。
谁能启发我?
最佳答案
首先,这里只有一个名为Princess
的类,即QueenA.Princess
。没有QueenB.Princess
-如果您编写QueenB.Princess
,则编译器只是将其理解为QueenA.Princess
。请注意,由于Princess
是QueenA
的非静态内部类(泛型类),因此QueenA.Princess
也是泛型类(由QueenA
的参数进行了参数化)。参数化后,它看起来像QueenA<something>.Princess
。
由于问题是类Princess
的两个值之间的兼容性,而我们上面已提到有一个这样的类,因此唯一的兼容性问题是有关泛型类型参数的。传递给super()
的类型应该是Q.Princess
。但是如上所述,Princess
属于QueenA
,而不是QueenB
或Q
。因此,编译器在编译时会自动将其重写为QueenA<something>.Princess
。问题是什么是something
。基本上,问题是Q
是QueenA<what>
。 Q
是绑定了QueenB<?>
的类型变量。这意味着某人可以使用Q
为QueenB<X>
且X
为满足QueenB
类型参数范围的任何类型(即扩展JokerB
的类型)的此类。因此,除了X
的子类型之外,我们无法假设有关JokerB
的任何内容。 QueenB<X>
扩展QueenA<X>
,这意味着Q
是QueenA<X>
。 <capture ...>
只是编译器打印以表示未知类型的内容。因此,在这一点上,编译器已经发现Q.Princess
的真正含义是QueenA<some unknown type that extends JokerB>.Princess
。
然后,将其传递给super()
(KingA
的构造函数)。此类型参数的参数类型也写为Q.Princess
(注意:这是KingA
的Q
,是不同的类型参数;请不要混淆)。如果您进行与上述相同的分析,您将看到编译器看到此Q.Princess
的真正含义是QueenA<some unknown type that extends JokerA>.Princess
。
问题是QueenA<first unknown subtype>.Princess
是QueenA<second unknown subtype>.Princess
的子类型吗?即first unknown subtype
与second unknown subtype
相同吗? (记住泛型是不变的。)编译器仅查看此内容便会说不知道它们是否相同,因为两个未知类型肯定会有所不同,因此它们是不兼容的。
您可能会说,等等,您知道Q
是某些未知类型QueenA<X>
的X
,KingB<Q>
被声明为扩展KingA<Q>
,因此Q
在KingB
范围内特定对象与Q
范围内的KingB
相同。因此,Q
是相同的,未知的X
在两种情况下都是相同的。但这不适用于这里,因为不再考虑Q
了。请记住,没有类型Q.Princess
。它表示的实际类型是QueenA<something>.Princess
。 QueenA<something>.Princess
是在编译时为每个类编译每个构造函数时弄清楚的。一旦确定为unknown type
,它将固定为unknown type
,并且与作为类的类型参数的Q
不相关。因此,这两个未知类型没有关系。
您可以通过使用新的类型参数解决问题,而不是让编译器推断未知类型。然后,可以使用type参数连接该类型的不同用途,以使编译器知道它们是同一类型。像这样:
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);
}
}