即使这不是一个好习惯,但我想知道为什么会这样做。
以下代码无法编译,我真的不明白为什么。
假设我有一个小丑,女王和国王的抽象定义:
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)
但是,我看不出公主课是如何与众不同的。
任何人都可以启发我吗?
答案 0 :(得分:1)
首先,这里只有一个名为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
类型参数边界的任何类型(即扩展{{1}的类型}})。因此,除了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
的{{1}},一个不同的类型参数;不要混淆)。如果您按照上述相同的分析,您将看到编译器发现此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
无关。所以两种未知类型没有关系。
您可以使用新的类型参数来解决它,而不是让编译器推断出未知类型。然后,type参数可以允许您连接类型的单独使用,以使编译器知道它们是相同的类型。像这样:
unknown type