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

我想将自定义类型的对象添加到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; } 

您应该覆盖自定义类型的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

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

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

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

}

您绝对可以覆盖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关于这个主题的章节。 这是一本非凡的书。

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

有关实现的详细信息,请参阅Joshua Bloch撰写的伟大的“Effective Java”一书中的这一章 。

关于:

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

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

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

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

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

正如SLaks已经指出的那样,重写equals()hashcode()方法绝对有意义。 要确保equals()方法按您希望的方式运行,请在方法中检查您认为区分两个对象的成员变量是否保持相同的值集。