3

我正在做一个纸牌游戏。无论如何,我都不知道如何从 ArrayList 中删除 Card。这是我正在使用的代码:

private List<Card> cardDeck = new ArrayList<Card>();

public void removeCard(Card card) {
    for (Iterator<Card> it = cardDeck.iterator(); it.hasNext();) {
        Card nextCard = it.next();
        if (nextCard.equals(card)) {
            cardDeck.remove(card);
            System.out.println("removed " + card);
        }
    }
}

这是卡片类,以防你需要它:

    public class Card {

    public Card(Rank rank, Suit suit) {
        this.rank = rank;
        this.suit = suit;
    }

    public Rank getRank() {
        return rank;
    }

    public Suit getSuit() {
        return suit;
    }

    @Override
    public String toString() {
        return getRank().toString().toLowerCase() + " of "
                + getSuit().toString().toLowerCase();
    }

    private Rank rank;

    private Suit suit;

}

我已经尝试了一切,但它不会删除。有小费吗?

4

5 回答 5

6

当你迭代一个集合时,你要删除一个项目的唯一remove方法是调用迭代器。所以你应该使用:

if (nextCard.equals(card)) {
    it.remove();
    System.out.println("removed " + card);
}

请注意,由于您没有覆盖equals,这实际上只是一个引用比较,因此您只会进入if语句的主体,如果nextCardcard是对完全相同的对象的引用。

当然如果你只是想要移除卡的方法,你应该可以将其更改为:

public void removeCard(Card card) {
    cardDeck.remove(card);
}

...当然,对平等有同样的警告。

为了覆盖equals(并且hashCode为了保持一致性),我首先会创建Card一个最终类,然后编写:

public final class Card {
    ...

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof Card)) {
            return false;
        }
        Card otherCard = (Card) other;
        return this.rank == otherCard.rank &&
               this.suit == otherCard.suit;
    }

    @Override
    public int hashCode() {
        int hash = 17;
        hash = hash * 31 + rank.hashCode();
        hash = hash * 31 + suit.hashCode();
        return hash;
    }
}

这是假设RankandSuit是枚举(对于引用相等性检查equals是适当的)。您可能还想在Card构造函数中添加无效检查。

于 2012-08-18T12:14:19.903 回答
3

在集合中使用对象时,最好覆盖equals()hashcode()。否则进行查找时相等条件可能会失败。

解决您的问题的另一种方法是:

使用it.remove()而不是cardDeck.remove(card);

例子:

for (Iterator<Card> it = cardDeck.iterator(); it.hasNext();) {
        Card nextCard = it.next();
        if (nextCard.equals(card)) {
            it.remove();
            System.out.println("removed " + card);
        }
    }
于 2012-08-18T12:14:47.330 回答
2

您的Card类实际上应该是一个enum,这将在每个不同的卡片和每个不同的 Java 对象之间强制建立一对一的关系。那么你就不需要实现equalsandhashCode并且实际上可以使用==而不是equals. 您可以Card在枚举中使用常量,使用非常有效的方法EnumSet等等。帮自己一个忙,使enum Card

于 2012-08-18T12:29:38.573 回答
0

在编写公共方法之前对其进行注释。用评论表明你的意图。它现在对我有帮助。

正如前面提到的那样,您应该使用迭代器来删除卡。

equals 方法没有很好地使用。因为你没有覆盖 Card 类中的 equals() 方法,所以 Object 类的 equals() 方法会被调用。如果 Card 实例相同,则此 equals 方法仅返回 true!这是 equals() 规范的一个非常特殊的情况。这是你的意图吗?如果是的话,写起来会更清楚:

if (nextCard == otherCard){..

相等通常意味着:

指示其他对象是否“等于”这个对象。

equals 方法在非空对象引用上实现等价关系:

It is reflexive: for any non-null reference value x, x.equals(x) should return true.
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns

真的。它是可传递的:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true 并且 y.equals(z) 返回 true,则 x.equals(z) 应该返回 true。它是一致的:对于任何非空引用值 x 和 y,x.equals(y) 的多次调用始终返回 true 或始终返回 false,前提是没有修改对象上 equals 比较中使用的信息。对于任何非空引用值 x,x.equals(null) 应该返回 false。

来源:http ://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals%28java.lang.Object%29

您是如何得出 remove 方法不起作用的结论的?

如果您以前使用过迭代器,则使用不应该使用的 ArrayList() 的 remove 方法。但是 ArrayList() 的 remove 方法有一个优点:它返回一个布尔值。始终检查返回值!因为在您的情况下,我认为必须始终移除卡,并且该方法是公开的,如果返回值为 false,您应该抛出异常。(在调用 remove() 之前卡片组会是空的吗?)

检查 remove 方法的另一种方法是检查 ArrayList 的大小是否减小。

于 2012-08-18T15:02:58.527 回答
0

首先,在迭代容器时删除某些内容不是一个好主意。其次,您必须实现该equals()方法。如果您还实现了该hashCode()方法,您将能够使用ArrayList's 的内置remove()方法,而不是编写自己的方法。

于 2012-08-18T12:13:43.527 回答