我想将自定义类型的对象添加到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;
}
答案 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)
您应该覆盖自定义类型的equals
和hashCode
方法。
但要小心,你可以在这里搞砸各种各样的东西:例如,如果你有自定义类型的子类型,你可能遇到其他同等问题:
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)
您绝对应该覆盖equals
和hashCode
,因为它们是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()
方法按照您的意愿运行 - 在方法中检查您认为区分两个对象的成员变量是否保持相同的值集。