如果要查找一個(gè)集合中是否包含了某個(gè)對(duì)象,那么就需要把這個(gè)對(duì)象和這個(gè)集合中的每個(gè)對(duì)象依次進(jìn)行比較和判斷,直到找到這個(gè)對(duì)象為止,或者把所有對(duì)象都比較一次為止(如果最后一個(gè)對(duì)象才是要查找的對(duì)象,或者集合中沒(méi)有包含要查找的對(duì)象)。當(dāng)集合中的對(duì)象數(shù)量較多時(shí),效率就很低。為了提高效率,提出了Hash算法。Hash算法對(duì)每一個(gè)對(duì)象都計(jì)算出一個(gè)Hash碼,根據(jù)Hash碼把對(duì)象分配到某個(gè)存儲(chǔ)區(qū)域中,比如一個(gè)集合包含了很多人,根據(jù)國(guó)籍,中國(guó)人是一個(gè)存儲(chǔ)區(qū)域,美國(guó)人是一個(gè)存儲(chǔ)區(qū)域,英國(guó)人是一個(gè)存儲(chǔ)區(qū)域,......。這樣如果要查找該集合是否包含了某個(gè)中國(guó)人,就到中國(guó)人的存儲(chǔ)區(qū)域去比較就行了,這樣大大提高了效率。
Java中實(shí)現(xiàn)了Hash的集合是HashSet。HashSet查找某個(gè)對(duì)象時(shí),首先用hashCode()方法計(jì)算出這個(gè)對(duì)象的Hash碼,然后再根據(jù)Hash碼到相應(yīng)的存儲(chǔ)區(qū)域用equals()方法查找,從而提高了效率。由于是集合,所以同一個(gè)對(duì)象只能有一個(gè)。
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類(lèi),然后定義了一個(gè)HashSet,并加入了5個(gè)Person到該集合,其中1個(gè)人加入了兩次,運(yùn)行結(jié)果如下:

可見(jiàn)Jack是同一個(gè)人,卻在集合中出現(xiàn)了兩次,這是什么原因呢?這是因?yàn)椋琍erson是Object的子類(lèi),而Object類(lèi)的equals()方法是根據(jù)對(duì)象的內(nèi)存地址來(lái)判斷兩個(gè)對(duì)象是否相等的,由于兩次插入的Jack的內(nèi)存地址肯定不相同,所以判斷的結(jié)果是不相等,所以?xún)纱味疾迦肓恕S谑牵覀冃枰矊?xiě)equals()方法來(lái)判斷兩個(gè)對(duì)象是否是同一個(gè)對(duì)象。
// 覆寫(xiě)equals方法 public boolean equals (Object obj){ // 地址相等,則肯定是同一個(gè)對(duì)象 if(this==obj){ return true; } // 類(lèi)型不同,則肯定不是同一類(lèi)對(duì)象 if(!(obj instanceof Person)){ return false; } // 類(lèi)型相同,向下轉(zhuǎn)型 Person per=(Person) obj; // 如果兩個(gè)對(duì)象的姓名和性別相同,則是同一個(gè)人 if(this.name.equals(per.name)&&this.sex.equals(per.sex)) return true; return false; }覆寫(xiě)equals()方法以后,運(yùn)行結(jié)果如下:

可見(jiàn)Jack仍然被插入了兩次,這是什么原因呢?這是因?yàn)镺bject的Hash碼返回的是對(duì)象的Hash地址,而兩個(gè)對(duì)象的Hash地址肯定是不相等的,所以6次插入的對(duì)象被存儲(chǔ)在6個(gè)存儲(chǔ)區(qū)域,equals()方法根本沒(méi)有運(yùn)行。于是,還需要覆寫(xiě)hashCode()方法,根據(jù)姓名來(lái)計(jì)算對(duì)象的Hash碼。
// 覆寫(xiě)hashCode方法 public int hashCode(){ return this.name.hashCode(); }運(yùn)行結(jié)果如下:

可見(jiàn),Jack只插入了一次,終于正確了。如果根據(jù)性別來(lái)計(jì)算對(duì)象的Hash碼,結(jié)果也是正確的,Jack也只會(huì)被插入1次。但是,如果兩個(gè)對(duì)象的性別不同,如下所示:
mySet.add(new Person("Jack","Male",190.0,95.0)); mySet.add(new Person("Jack","Female",190.0,95.0));則兩個(gè)對(duì)象都會(huì)被插入:

這是因?yàn)殡m然兩個(gè)對(duì)象的Hash碼相同(不論是按照姓名,還是按照性別來(lái)計(jì)算,Hash碼都是相同的),但是equals()方法判斷這兩個(gè)對(duì)象不相等,于是都插入了。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注