为了在散列表中将自己的类作为键使用,必须同时覆盖hashCode()和equals()。
看一个例子:
package com.cqdxwjd.chapter8;
import java.util.Hashtable;
class Groundhog {
int ghNumber;
Groundhog(int n) {
ghNumber = n;
}
}
class Prediction {
boolean shadow = Math.random() > 0.5;
public String toString() {
if (shadow)
return "Six more weeks of Winter!";
else
return "Early Spring!";
}
}
public class SpringDetector {
public static void main(String[] args) {
Hashtable ht = new Hashtable();
for (int i = 0; i < 10; i++)
ht.put(new Groundhog(i), new Prediction());
System.out.println("ht = " + ht + "\n");
System.out.println("Looking up prediction for groundhog #3:");
Groundhog gh = new Groundhog(3);
if (ht.containsKey(gh))
System.out.println((Prediction) ht.get(gh));
}
}
运行结果为:
ht = {com.cqdxwjd.chapter8.Groundhog@3219ab8d=Early Spring!, com.cqdxwjd.chapter8.Groundhog@1cf15b84=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog@65b1fd9c=Early Spring!, com.cqdxwjd.chapter8.Groundhog@334dcfad=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog@88140ed=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog@5dcd8bf7=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog@11b75be2=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog@5d0769dd=Early Spring!, com.cqdxwjd.chapter8.Groundhog@29af45f4=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog@61a0353d=Six more weeks of Winter!}
Looking up prediction for groundhog #3:
可以看到最后查找标号为3的Groundhog时,没有结果。因为Groundhog是从通用的Object根类继承的。事实上是用Object的hashCode()方法生成每个对象的散列码,而且默认情况下只使用它的对象地址。所以,Groundhog(3)的第一个实例并不会产生与
Groundhog(3)第二个实例相等的散列码,而我们用第二个实例进行检索。
大家或许认为此时要做的全部事情就是正确地覆盖hashCode()。但这样做依然行不能,除非再做另一件事情:覆盖也属于Object 一部分的equals()。当散列表试图判断我们的键是否等于表内的某个键时,就会用到这个方法。同样地,默认的Object.equals()只是简单地比较对象地址,所以一个Groundhog(3)并不等于另一个Groundhog(3)。因此,为了在散列表中将自己的类作为键使用,必须同时覆盖hashCode()和equals(),就象下面展示的那样:
package com.cqdxwjd.chapter8;
import java.util.Hashtable;
class Groundhog2 {
int ghNumber;
Groundhog2(int n) {
ghNumber = n;
}
public int hashCode() {
return ghNumber;
}
public boolean equals(Object o) {
return (o instanceof Groundhog2)
&& (ghNumber == ((Groundhog2) o).ghNumber);
}
}
class Prediction {
boolean shadow = Math.random() > 0.5;
public String toString() {
if (shadow)
return "Six more weeks of Winter!";
else
return "Early Spring!";
}
}
public class SpringDetector2 {
public static void main(String[] args) {
Hashtable ht = new Hashtable();
for (int i = 0; i < 10; i++)
ht.put(new Groundhog2(i), new Prediction());
System.out.println("ht = " + ht + "\n");
System.out.println("Looking up prediction for groundhog #3:");
Groundhog2 gh = new Groundhog2(3);
if (ht.containsKey(gh))
System.out.println((Prediction) ht.get(gh));
}
}
运行结果为:
ht = {com.cqdxwjd.chapter8.Groundhog2@9=Early Spring!, com.cqdxwjd.chapter8.Groundhog2@8=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog2@7=Early Spring!, com.cqdxwjd.chapter8.Groundhog2@6=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog2@5=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog2@4=Early Spring!, com.cqdxwjd.chapter8.Groundhog2@3=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog2@2=Early Spring!, com.cqdxwjd.chapter8.Groundhog2@1=Six more weeks of Winter!, com.cqdxwjd.chapter8.Groundhog2@0=Six more weeks of Winter!}
Looking up prediction for groundhog #3:
Six more weeks of Winter!