由于参数是静态的,我在尝试将参数传递给父通用类的构造函数时遇到问题,因此我必须在编译时显式指定类型。
以下是有关的两个类:
public class CardStack<T extends Card> extends ArrayList<T>
public class Deck<T extends Card> extends CardStack<T>
我需要“T扩展卡”而不仅仅是卡的原因是因为我在客户端(需要渲染它们)和服务器(只关心值)之间共享这些类。
我静静地制作了一副牌,在放入每个牌组后将被洗牌。
private static final CardStack<Card> NEW_DECK;
static {
NEW_DECK = new CardStack<>(DECK_SIZE);
for (int i = 0; i < DECK_SIZE; i++) {
NEW_DECK.push(new Card(Card.Suit.values()[i / Card.CARD_VALUE_MAX],
i % Card.CARD_VALUE_MAX + 1));
}
}
Deck的构造函数:
public Deck() {
super(NEW_DECK); // Error Here
Collections.shuffle(this);
}
CardStack的构造函数:
protected CardStack(final CardStack<? extends T> cardStack) {
super(cardStack);
}
我无法弄清楚要放什么“?延伸T”。我尝试过各种各样的东西,但似乎什么都没有用,所以我似乎并不完全明白发生了什么。这种设计可行吗?如果不是什么会是一个更好的解决方案。谢谢!
=============================================== ==========================
编辑:更好地解释使用泛型的推理。
首先,我想在客户端和服务器之间共享这些类,我已经在上面说过了。真正的问题是当我尝试扩展这些类来渲染它们时。所有Client类都包含用于呈现的信息和方法(x / y coord,绘制和检测点击的方法)。
这适用于我的班级ClientCard extends Card
,但是当我尝试制作ClientCardStack extends CardStack
因为CardStack包含卡片时出现问题,我无法渲染它们,因为它们不包含正确的信息,以及什么我真的需要ClientCardStack extends CardStack<ClientCard>
导致所有这些问题。
答案 0 :(得分:2)
问题是NEW_DECK
的类型为CardStack<Card>
,而您调用的超级构造函数需要CardStack<? extends T>
。 T
并不总是Card
的超类。
对此最好的解决方案实际上不使用泛型。继承规定无论您是拥有客户端版本的实例还是服务器版本,您仍然拥有Card
的实例,因此当您不知道自己是客户端还是客户端时,请使用Card
服务器
答案 1 :(得分:0)
让我们检查Deck
构造函数:
public Deck() {
super(NEW_DECK); // supposed to invoke CardStack<T>
Collections.shuffle(this);
}
那么,我们在NEW_DECK
:
private static final CardStack<Card> NEW_DECK;
关键是此<Card>
不是<T>
。如果您尝试将通配符添加到NEW_DECK
:
private static final CardStack<T> NEW_DECK;
// Warning: Cannot make a static reference to a non-static type
想象一下来电者:
Deck<Card2> deck = new Deck();
此deck
- 左手类型为Deck<Card2>
,右手类型为Deck<Card>
。直观地说,它应该是正确的。不幸的是,java泛型不是不变的。它取而代之的是 invariant 。即Deck<Card2>
不 是Deck<Card>
的子类型。
您需要在构造函数中显式定义类型。 E.g:
public static final CardStack<Card> NEW_DECK; // public now
public Deck() { // creates an empty deck
super(16);
}
public Deck(CardStack<T> stack) {
super(stack);
Collections.shuffle(this);
}
您可以像这样调用第二个构造函数:
public static void main(String[] args) {
Deck<Card> deck = new Deck(NEW_DECK);
}
我认为这些改变会改变你的设计。但是他们以一种好的方式做到了!他们强迫你做某种dependency injection。