如何为Java对象定义“相同性”?

时间:2011-03-07 15:14:46

标签: java equality

我想将自定义类型的对象添加到Set中。我有几个是相同的,即它们的公共变量具有相同的值。

我不希望将多个“相同”对象的实例添加到集合中,但每次创建新对象时都会添加它。

这是因为类Object的equals方法在对象上实现了最有区别的可能等价关系:“对于任何非空引用值x和y,当且仅当x和y引用同一对象时,此方法返回true (x == y的值为true)。“

我可以覆盖此对象的equals方法以不同方式定义它吗?

感谢大家解决了问题

通过覆盖Java Object的equals()方法来定义java对象的相同性。

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((uri == null) ? 0 : uri.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Resource))
        return false;
    Resource other = (Resource) obj;
    if (uri == null) {
        if (other.uri != null)
            return false;
    } else if (!uri.equals(other.uri))
        return false;
    return true;
}

8 个答案:

答案 0 :(得分:5)

您需要覆盖equals() hashCode() 方法,告诉HashSet您认为相同的内容。

如果您正在使用TreeSet,则应该实现Comparable

答案 1 :(得分:2)

正如SLaks所说,您应该覆盖equals()hashCode()方法。当您覆盖equals()时,您会考虑这些值,例如:

public class MyObject
  public int x;
  public int y;

  public boolean equals(Object obj) {
    return (obj instance of MyObject) && (obj.x==x && obj.y==y);
  }

  public int hashCode() { 
   return (x+y)*31;
  }

}

答案 2 :(得分:2)

您应该覆盖自定义类型的equalshashCode方法。

但要小心,你可以在这里搞砸各种各样的东西:例如,如果你有自定义类型的子类型,你可能遇到其他同等问题:

class Point {
    final int x;
    final int y;

    public Point(int x, int y) {
        this.x= x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) return true;   //If objects equal, is OK
        if (o instanceof Point) {
           Point that = (Point)o;
           return (x == that.x)  && y == that.y);
        }
        return false;
    }
}

class ColoredPoint extends Point {
   final Color color;
   ColoredPoint(int x, int y, Color color) {
      super(x, y);
      this.color = color
   }
}

Point p1 = new Point(1, 2);
ColoredPoint cp1 = new ColoredPoint(1, 2, Color.BLUE);
ColoredPoint cp1 = new ColoredPoint(1, 2, Color.RED);

目前,p1,cp1和cp2都是相同的。但是,显然cp1和cp2不相等。您还需要在ColoredPoint中实现equals,以比较ColoredPoint Objects(但这会破坏p1和cp1或cp2之间的相等性)。

另外,请确保您的等号具有上述签名。将其定义为public equals(Point that)...是一个常见的错误,这是错误的。

有关equals和hashCode

规则的完整说明,请参阅http://www.artima.com/lejava/articles/equality.html

答案 3 :(得分:1)

您绝对应该覆盖equalshashCode,因为它们是Java用来定义对象相等性的方法。默认情况下,所有Objects都不同。

有关实施的详细信息,请参阅Joshua Bloch撰写的伟大的“Effective Java”一书中的this chapter

答案 4 :(得分:1)

您绝对可以覆盖equals()来比较班级中的重要字段。但是,要记住一些重要的事情。来自http://www.javapractices.com/topic/TopicAction.do?Id=17

- 如果覆盖等于,则必须覆盖hashCode。

-hashCode必须为相等的对象生成相等的值。

-equals和hashCode必须依赖于同一组“重要”字段。您必须在这两种方法中使用相同的字段集。您不需要使用所有字段。例如,很可能从equals和hashCode中省略了依赖于其他字段的计算字段。

这基本上是因为Set数据结构是作为哈希集实现的;它需要hashCode()将对象放在底层数组中并在以后找到它,并且它需要equals()来解决散列冲突(即散列到相同值的多个对象)。

这是关于实现hashCode()的一个很好的指南:http://www.javamex.com/tutorials/collections/hash_function_guidelines.shtml

[编辑]

我想请kostja的建议来阅读Josh Bloch关于这个主题的章节。这是一本非凡的书。

答案 5 :(得分:1)

关于:

  

我觉得我的问题是   两者不相等,因为他们   碰巧是不同的对象   具有相同的价值。

equals的默认实现执行最严格的操作 - 文档说最具辨别力的 - 可能的等式测试形式,即测试身份 (即两个引用引用内存中的相同位置)。

这是一种平等形式,但并不总是最有用的。通常,您要测试的是两个对象具有相同的属性。这是一件非常自然的事情,想做什么,不值得任何焦虑。

答案 6 :(得分:0)

添加Set的功能,检查hashcode()方法&如果它返回true,那么它将调用equal()。每个对象具有不同的存储位置和Object类的equals()只比较内存位置位以检查相等性。因此,每个对象都会被添加。

要使其工作,您必须将hashCode()和equals()方法添加到您的类中,这些将比较特定于类的属性,根据您创建相同的含义。

答案 7 :(得分:0)

正如SLaks已经指出的那样,覆盖equals()hashcode()方法绝对有意义。为了确保equals()方法按照您的意愿运行 - 在方法中检查您认为区分两个对象的成员变量是否保持相同的值集。