以前一直不是很理解为何要重写HashCode和Equals方法,才只能做为键值存储在HashMap中。经过下文,能够一探究竟。java
首先,若是咱们直接用如下的Person类做为键,存入HashMap中,会发生发生什么状况呢?segmentfault
public class Person {ide
private String id;this
public Person(String id) {spa
this.id = id;对象
}字符串
}get
import java.util.HashMap;hash
public class Main {class
public static void main(String[] args) {
HashMap<Person, String> map = new HashMap<Person, String>();
map.put(new Person("001"), "findingsea");
map.put(new Person("002"), "linyin");
map.put(new Person("003"), "henrylin");
map.put(new Person("003"), "findingsealy");
System.out.println(map.toString());
System.out.println(map.get(new Person("001")));
System.out.println(map.get(new Person("002")));
System.out.println(map.get(new Person("003")));
}
}
那么输出结果是什么呢?
{Person@6e4d4d5e=henrylin, Person@275cea3=findingsea, Person@15128ee5=findingsealy, Person@4513098=linyin}
null
null
null
咱们能够看到,这里出现了两个问题:
那么,正确的方法其实在不少地方都是被描述过了,直接对Person类进行修改,重载equals和hashCode方法,修改事后的Person类以下:
public class Person {
private String id;
public Person(String id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (id != null ? !id.equals(person.id) : person.id != null) return false;
return true;
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}
那么,当咱们从新执行上述的检验程序时,获得的结果以下:
{Person@ba31=findingsea, Person@ba32=linyin, Person@ba33=findingsealy}
findingsea
linyin
findingsealy
能够看到,以前指出的亮点错误都获得了改正。那么,为何会这样呢?
在HashMap中,查找key的比较顺序为:
显然,第一步就是要用到hashCode()方法,而第二步就是要用到equals()方法。在没有进行重载时,在这两步会默认调用Object类的这两个方法,而在Object中,Hash Code的计算方法是根据对象的地址进行计算的,那两个Person("003")的对象地址是不一样的,因此它们的Hash Code也不一样,天然HashMap也不会把它们当成是同一个key了。同时,在Object默认的equals()中,也是根据对象的地址进行比较,天然一个Person("003")和另外一个Person("003")是不相等的。
理解了这一点,就很容易搞清楚为何须要同时重载hashCode()和equals两个方法了。
还有一个细节,在Person类中对于hashCode()的重在方法为:
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
这里可能有疑惑的点在于:为何能够用String类型的变量的Hash Code做为Person类的Hash Code值呢?这样new Person(new String("003"))和new Person(new String("003"))的Hash Code是相等的吗?
来看看如下代码的输出:
System.out.println("findingsea".hashCode());
System.out.println("findingsea".hashCode());
System.out.println(new String("findingsea").hashCode());
System.out.println(new String("findingsea").hashCode());
728795174
728795174
728795174
728795174
能够看到四条语句的输出都是相等的,很直观的合理的猜想就是String类型也重载了hashCode()以根据字符串的内容来返回Hash Code值,因此相同内容的字符串具备相同的Hash Code。
同时,这也说明了一个问题:为何在已知hashCode()相等的状况下,还须要用equals()进行比较呢?就是由于避免出现上述例子中的出现的状况,由于根据对Person类的hashCode()方法的重载实现,Person类会直接用id这个String类型成员的Hash Code值做为本身的Hash Code值,可是很显然的,一个Person("003")和一个String("003")是不相等的,因此在hashCode()相等的状况下,还须要用equals()进行比较。
如下例子能够做为上述说明的佐证:
System.out.println(new Person("003").hashCode()); // 47667
System.out.println(new String("003").hashCode()); // 47667
System.out.println(new Person("003").equals(new String("003"))); // false
以上便是所有。
参考:https://segmentfault.com/a/1190000002655085