将静态字段作为通用类型传递

时间:2016-08-27 20:51:21

标签: java generics

由于参数是静态的,我在尝试将参数传递给父通用类的构造函数时遇到问题,因此我必须在编译时显式指定类型。

以下是有关的两个类:

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>导致所有这些问题。

2 个答案:

答案 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