我正在开发纸牌游戏。无论如何,我无法弄清楚如何从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;
}
我已经尝试了一切,但它不会删除。有什么提示吗?
答案 0 :(得分:6)
当你在一个集合上进行迭代时,你只想删除项目的 方法是在迭代器上调用remove
。所以你应该使用:
if (nextCard.equals(card)) {
it.remove();
System.out.println("removed " + card);
}
请注意,由于您没有覆盖equals
,这实际上只是一个引用比较,因此您只会进入if
语句的主体。 nextCard
和card
是对完全相同的对象的引用。
当然,如果只是想要删除卡片的方法,您应该可以将其更改为:
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;
}
}
假设Rank
和Suit
是枚举(对于equals
中的引用相等性检查是合适的)。您可能也希望在Card
构造函数中添加无效性检查。
答案 1 :(得分:2)
您的Card
类应该是enum
,它会强制每个不同的卡与每个不同的Java对象之间建立一对一的关系。然后,您不需要实施equals
和hashCode
,实际上可以使用==
代替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的大小是否已减少。