最近我读了这篇文章 开发人员工作文件。
该文档是关于有效和正确地定义hashCode()和equals(),但我无法弄清楚为什么我们需要覆盖这两个方法。
我如何决定有效地实现这些方法?
最近我读了这篇文章 开发人员工作文件。
该文档是关于有效和正确地定义hashCode()和equals(),但我无法弄清楚为什么我们需要覆盖这两个方法。
我如何决定有效地实现这些方法?
当前回答
Java提出了一个规则
如果使用Object类的equals方法,两个对象相等,那么hashcode方法应该为这两个对象提供相同的值。
因此,如果在我们的类中重写equals(),我们也应该重写hashcode()方法来遵循此规则。 例如,equals()和hashcode()这两个方法都用于Hashtable中以键值对的形式存储值。如果我们覆盖其中一个而不是另一个,如果我们使用这样的对象作为键,哈希表可能不会像我们想要的那样工作。
其他回答
因为如果你不重写它们,你将使用Object中的默认实现。
考虑到实例相等和hascode值通常需要了解组成对象的内容,它们通常需要在类中重新定义,以具有任何有形的意义。
hashCode ():
如果只重写hash-code方法,什么也不会发生,因为它总是为每个对象返回一个新的hashCode作为object类。
equals ():
如果你只覆盖equals方法,如果a.equals(b)为真,这意味着a和b的hashCode必须是相同的,但这不会发生,因为你没有覆盖hashCode方法。
注意:Object类的hashCode()方法总是为每个对象返回一个新的hashCode。
因此,当您需要在基于哈希的集合中使用对象时,必须重写equals()和hashCode()。
如果重写equals()而不是hashcode(),则不会发现任何问题,除非您或其他人在HashSet等散列集合中使用该类类型。 在我之前的人已经清楚地解释了很多次文献理论,我只是在这里提供一个非常简单的例子。
考虑一个类,它的equals()需要表示自定义的东西:-
public class Rishav {
private String rshv;
public Rishav(String rshv) {
this.rshv = rshv;
}
/**
* @return the rshv
*/
public String getRshv() {
return rshv;
}
/**
* @param rshv the rshv to set
*/
public void setRshv(String rshv) {
this.rshv = rshv;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Rishav) {
obj = (Rishav) obj;
if (this.rshv.equals(((Rishav) obj).getRshv())) {
return true;
} else {
return false;
}
} else {
return false;
}
}
@Override
public int hashCode() {
return rshv.hashCode();
}
}
现在考虑这个主类:-
import java.util.HashSet;
import java.util.Set;
public class TestRishav {
public static void main(String[] args) {
Rishav rA = new Rishav("rishav");
Rishav rB = new Rishav("rishav");
System.out.println(rA.equals(rB));
System.out.println("-----------------------------------");
Set<Rishav> hashed = new HashSet<>();
hashed.add(rA);
System.out.println(hashed.contains(rB));
System.out.println("-----------------------------------");
hashed.add(rB);
System.out.println(hashed.size());
}
}
这将产生以下输出:-
true
-----------------------------------
true
-----------------------------------
1
我对结果很满意。但是如果我没有覆盖hashCode(),它将导致噩梦,因为具有相同成员内容的Rishav对象将不再被视为唯一的hashCode将是不同的,因为由默认行为生成,这里将是输出:-
true
-----------------------------------
false
-----------------------------------
2
常见错误如下例所示。
public class Car {
private String color;
public Car(String color) {
this.color = color;
}
public boolean equals(Object obj) {
if(obj==null) return false;
if (!(obj instanceof Car))
return false;
if (obj == this)
return true;
return this.color.equals(((Car) obj).color);
}
public static void main(String[] args) {
Car a1 = new Car("green");
Car a2 = new Car("red");
//hashMap stores Car type and its quantity
HashMap<Car, Integer> m = new HashMap<Car, Integer>();
m.put(a1, 10);
m.put(a2, 20);
System.out.println(m.get(new Car("green")));
}
}
绿色的车没有找到
2. hashCode()引起的问题
该问题是由未覆盖的hashCode()方法引起的。equals()和hashCode()之间的契约是:
如果两个对象相等,那么它们必须具有相同的哈希码。 如果两个对象具有相同的哈希码,则它们可能相等,也可能不相等。 公共int hashCode(){ 返回this.color.hashCode (); }
为了在HashMap, Hashtable等集合中使用我们自己的类对象作为键。,我们应该通过了解集合的内部工作来重写这两个方法(hashCode()和equals())。否则,它会导致我们意想不到的错误结果。