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

问题描述 投票:4回答:8

我想将自定义类型的对象添加到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;
}
java equality
8个回答
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之间的相等性)。

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

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


5
投票

你需要覆盖equals()hashCode()方法来告诉HashSet你认为平等的东西。

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


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;
  }

}


1
投票

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

- 如果重写equals,则必须覆盖hashCode。

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

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

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

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

[编辑]

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


1
投票

你绝对应该覆盖equalshashCode,因为它们是Java用来定义对象相等性的方法。默认情况下,所有Objects都不同。 有关实现的详细信息,请参阅Josaz Bloch撰写的伟大的“Effective Java”一书中的this chapter


1
投票

关于:

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

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

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


0
投票

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

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


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.