无法从ArrayList中删除对象

时间:2012-08-18 12:12:22

标签: java

我正在开发纸牌游戏。无论如何,我无法弄清楚如何从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;

}

我已经尝试了一切,但它不会删除。有什么提示吗?

5 个答案:

答案 0 :(得分: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;
    }
}

假设RankSuit是枚举(对于equals中的引用相等性检查是合适的)。您可能也希望在Card构造函数中添加无效性检查。

答案 1 :(得分:2)

您的Card类应该是enum,它会强制每个不同的卡与每个不同的Java对象之间建立一对一的关系。然后,您不需要实施equalshashCode,实际上可以使用==代替equals。您可以在枚举中使用Card常量,使用非常高效的EnumSet等等。帮自己一个忙,并enum Card

答案 2 :(得分:1)

在集合中使用对象时,最好覆盖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);
        }
    }

答案 3 :(得分:0)

首先,在迭代容器时删除某些东西并不是一个好主意。其次,您必须实现equals()方法。如果您还实施了hashCode()方法,则可以使用ArrayList的内置remove()方法,而不是编写自己的方法。

答案 4 :(得分:0)

在编写公共方法之前对其进行注释。通过评论证明您的意图。它现在对我很有用。

如前所述,你应该使用迭代器删除卡片。

equals方法使用不当。因为您没有覆盖Card类中的equal()方法,所以将调用Object类的equals()方法。如果Card实例相同,则此equals方法仅返回true!这是equals()规范的一个非常特殊的情况。这是你的意图吗?如果是,那么写一下会更清楚:

if(nextCard == otherCard){..

通常意味着:

  

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

     

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

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   对象的比较被修改。       对于任何非空引用值x,x.equals(null)应返回false。

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

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

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

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