如果要查找一個集合中是否包含了某個對象,那麼就需要把這個對象和這個集合中的每個對象依次進行比較和判斷,直到找到這個對象為止,或者把所有對象都比較一次為止(如果最後一個對象才是要查找的對象,或者集合中沒有包含要查找的對象)。當集合中的對象數量較多時,效率就很低。為了提高效率,提出了Hash算法。Hash算法對每一個對象都計算出一個Hash碼,根據Hash碼把對象分配到某個存儲區域中,比如一個集合包含了很多人,根據國籍,中國人是一個存儲區域,美國人是一個存儲區域,英國人是一個存儲區域,......。這樣如果要查找該集合是否包含了某個中國人,就到中國人的存儲區域去比較就行了,這樣大大提高了效率。
Java中實現了Hash的集合是HashSet。HashSet查找某個對象時,首先用hashCode()方法計算出這個對象的Hash碼,然後再根據Hash碼到相應的存儲區域用equals()方法查找,從而提高了效率。由於是集合,所以同一個對象只能有一個。
hashSet的例子如下所示:
package my;
import java.util.HashSet;
import java.util.Set;
class Person{
// 性別
String sex;
// 姓名
String name;
// 身高
Double hei;
// 體重
Double wei;
public Person(String n, String s, Double h, Double w){
this.name=n;
this.sex=s;
this.hei=h;
this.wei=w;
}
public String toString(){
return "\n姓名:"+this.name+" 性別:"+this.sex+" 身高:"+this.hei+" 體重:"+this.wei;
}
}
public class myHS {
private static Set<Person> mySet = new HashSet<Person>();
public static void main(String[] args) {
mySet.add(new Person("Tom","Male",170.0,70.0));
mySet.add(new Person("Peter","Male",175.0,70.0));
mySet.add(new Person("Kate","Female",168.0,60.0));
mySet.add(new Person("Alice","Female",161.0,55.0));
mySet.add(new Person("Jack","Male",190.0,95.0));
mySet.add(new Person("Jack","Male",190.0,95.0));
System.out.println(mySet);
}
}
以上例子先定義了Person類,然後定義了一個HashSet,並加入了5個Person到該集合,其中1個人加入了兩次,運行結果如下:
可見Jack是同一個人,卻在集合中出現了兩次,這是什麼原因呢?這是因為,Person是Object的子類,而Object類的equals()方法是根據對象的內存地址來判斷兩個對象是否相等的,由於兩次插入的Jack的內存地址肯定不相同,所以判斷的結果是不相等,所以兩次都插入了。於是,我們需要覆寫equals()方法來判斷兩個對象是否是同一個對象。
// 覆寫equals方法
public boolean equals (Object obj){
// 地址相等,則肯定是同一個對象
if(this==obj){
return true;
}
// 類型不同,則肯定不是同一類對象
if(!(obj instanceof Person)){
return false;
}
// 類型相同,向下轉型
Person per=(Person) obj;
// 如果兩個對象的姓名和性別相同,則是同一個人
if(this.name.equals(per.name)&&this.sex.equals(per.sex))
return true;
return false;
}
覆寫equals()方法以後,運行結果如下:
可見Jack仍然被插入了兩次,這是什麼原因呢?這是因為Object的Hash碼返回的是對象的Hash地址,而兩個對象的Hash地址肯定是不相等的,所以6次插入的對象被存儲在6個存儲區域,equals()方法根本沒有運行。於是,還需要覆寫hashCode()方法,根據姓名來計算對象的Hash碼。
// 覆寫hashCode方法
public int hashCode(){
return this.name.hashCode();
}
運行結果如下:
可見,Jack只插入了一次,終於正確了。如果根據性別來計算對象的Hash碼,結果也是正確的,Jack也只會被插入1次。但是,如果兩個對象的性別不同,如下所示:
mySet.add(new Person("Jack","Male",190.0,95.0));
mySet.add(new Person("Jack","Female",190.0,95.0));
則兩個對象都會被插入:
這是因為雖然兩個對象的Hash碼相同(不論是按照姓名,還是按照性別來計算,Hash碼都是相同的),但是equals()方法判斷這兩個對象不相等,於是都插入了。