Java 比较两个相同的对象给出 false
Java Comparing two identical objects gives false
我有一个名为 Card
的自定义 class
public class Card implements Serializable, Comparable<Card>{
private static final long serialVersionUID = 100L;
private Rank rank;
private Suit suit;
public Card(Rank rank, Suit suit){
this.rank = rank;
this.suit = suit;
}
public enum Rank{
TWO(2), THREE(3), FOUR(4), FIVE(5), SIX(6), SEVEN(7), EIGHT(8), NINE(9), TEN(10), JACK(10), QUEEN(10), KING(10), ACE(11);
private final int value;
Rank(int value){
this.value = value;
}
}
public enum Suit{
CLUBS, DIAMONDS, HEARTS, SPADES;
public static Suit getSuit(){
Random rand = new Random();
return values()[rand.nextInt(values().length)];
}
}
为了检查它们是否相同,我正在这样做:
Card smth = new Card(Card.Rank.ACE,Card.Suit.CLUBS);
Card smth1 = new Card(Card.Rank.ACE,Card.Suit.CLUBS);
System.out.println(smth.equals(smth1));
但它总是给我 false
我不知道为什么会这样,我也尝试将它们放入 ArrayList
并使用 contains()
检查但输出是一样。
您的 Card class 必须覆盖 equals
以定义何时应将两个 Card 实例视为相等。
@Override
public boolean equals (Object other)
{
if (this == other)
return true;
if (!(other instanceof Card))
return false;
Card oc = (card) other;
return this.rank.equals(oc.rank) && this.suit.equals(other.quit);
}
同时覆盖hashCode
,这样如果两张卡片彼此相等,它们的哈希码也将相等。
equals()
的默认实现通过内存中的地址比较对象。意味着不同的对象将被认为是不平等的。这叫做按身份比较。
当您想按值比较对象时,您必须创建自己的 equals 方法,该方法比较 rank
和 suit
的值。这可能很困难,因为您还必须验证两个对象都不为 null 并且非常对象类型才能安全地从 Object
转换它。这称为按值比较。
一个有用的提示是使用 Eclipse 生成 equals 函数。
equals
的默认实现只考虑引用相等,即v1==v2。这样,包含相同值的两个不同实例不会比较相等。您可以选择以下两种策略之一:
- 对于表示相同信息的对象,覆盖等于 return true。通常,这意味着以某种方式比较两个对象的字段。某些字段的值可能无关紧要,例如如果您的对象保留某种缓存,则 equals 方法可能会在比较时忽略它。注意还需要重写hashcode方法才能和equals保持一致。
- 设计您的 class 以便每个不同的概念 "value" 只创建一个实例。显然,这不适用于可变的或非最终的 classes,但您不需要覆盖 equals 或 hashcode。这就是枚举的作用:每个枚举值只存在一个实例,因此您可以将它们与 == 进行比较。为了走这条路,您需要禁用可公开访问的构造函数,并提供某种工厂方法来 return 或(如果以前从未创建过)构造有问题的实例。缺点是对于大量不同的值,此路由会浪费大量内存。
我有一个名为 Card
的自定义 classpublic class Card implements Serializable, Comparable<Card>{
private static final long serialVersionUID = 100L;
private Rank rank;
private Suit suit;
public Card(Rank rank, Suit suit){
this.rank = rank;
this.suit = suit;
}
public enum Rank{
TWO(2), THREE(3), FOUR(4), FIVE(5), SIX(6), SEVEN(7), EIGHT(8), NINE(9), TEN(10), JACK(10), QUEEN(10), KING(10), ACE(11);
private final int value;
Rank(int value){
this.value = value;
}
}
public enum Suit{
CLUBS, DIAMONDS, HEARTS, SPADES;
public static Suit getSuit(){
Random rand = new Random();
return values()[rand.nextInt(values().length)];
}
}
为了检查它们是否相同,我正在这样做:
Card smth = new Card(Card.Rank.ACE,Card.Suit.CLUBS);
Card smth1 = new Card(Card.Rank.ACE,Card.Suit.CLUBS);
System.out.println(smth.equals(smth1));
但它总是给我 false
我不知道为什么会这样,我也尝试将它们放入 ArrayList
并使用 contains()
检查但输出是一样。
您的 Card class 必须覆盖 equals
以定义何时应将两个 Card 实例视为相等。
@Override
public boolean equals (Object other)
{
if (this == other)
return true;
if (!(other instanceof Card))
return false;
Card oc = (card) other;
return this.rank.equals(oc.rank) && this.suit.equals(other.quit);
}
同时覆盖hashCode
,这样如果两张卡片彼此相等,它们的哈希码也将相等。
equals()
的默认实现通过内存中的地址比较对象。意味着不同的对象将被认为是不平等的。这叫做按身份比较。
当您想按值比较对象时,您必须创建自己的 equals 方法,该方法比较 rank
和 suit
的值。这可能很困难,因为您还必须验证两个对象都不为 null 并且非常对象类型才能安全地从 Object
转换它。这称为按值比较。
一个有用的提示是使用 Eclipse 生成 equals 函数。
equals
的默认实现只考虑引用相等,即v1==v2。这样,包含相同值的两个不同实例不会比较相等。您可以选择以下两种策略之一:
- 对于表示相同信息的对象,覆盖等于 return true。通常,这意味着以某种方式比较两个对象的字段。某些字段的值可能无关紧要,例如如果您的对象保留某种缓存,则 equals 方法可能会在比较时忽略它。注意还需要重写hashcode方法才能和equals保持一致。
- 设计您的 class 以便每个不同的概念 "value" 只创建一个实例。显然,这不适用于可变的或非最终的 classes,但您不需要覆盖 equals 或 hashcode。这就是枚举的作用:每个枚举值只存在一个实例,因此您可以将它们与 == 进行比较。为了走这条路,您需要禁用可公开访问的构造函数,并提供某种工厂方法来 return 或(如果以前从未创建过)构造有问题的实例。缺点是对于大量不同的值,此路由会浪费大量内存。