我思故我強(qiáng)

          Set中equals()和hashCode()

          equals()是判讀兩個(gè)Set是否相等[前提是equals()在類中被覆蓋]。==決定引用值是否指向同一對(duì)象。

          1、當(dāng)向集合set中增加對(duì)象時(shí),首先計(jì)算要增加對(duì)象的hashCode碼,根據(jù)該值來得到一個(gè)位置來存放當(dāng)前的對(duì)象,當(dāng)在該位置沒有一個(gè)對(duì)象存在的話,那么集合set認(rèn)為該對(duì)象在集合中不存在,直接增加進(jìn)去。如果在該位置有一個(gè)對(duì)象的話,接著將準(zhǔn)備增加到集合中的對(duì)象與該位置上的對(duì)象進(jìn)行equals方法比較,如果該equals方法返回false,那么集合認(rèn)為集合中不存在該對(duì)象,再進(jìn)行一次散列,將該對(duì)象放到散列后計(jì)算出的新地址里,如果equals方法返回true,那么集合認(rèn)為集合中已經(jīng)存在該對(duì)象了,不會(huì)再將該對(duì)象增加到集合中了。

          2、當(dāng)重寫equals方法時(shí),必須要重寫hashCode方法。在java的集合中,判斷兩個(gè)對(duì)象是否相等的規(guī)則是:

          1),判斷兩個(gè)對(duì)象的hashCode是否相等

                如果不相等,認(rèn)為兩個(gè)對(duì)象也不相等,完畢 ; 如果相等,轉(zhuǎn)入2

          2),判斷兩個(gè)對(duì)象用equals運(yùn)算是否相等

                如果不相等,認(rèn)為兩個(gè)對(duì)象也不相等

                如果相等,認(rèn)為兩個(gè)對(duì)象相等(equals()是判斷兩個(gè)對(duì)象是否相等的關(guān)鍵)

              可見hashcode()相等時(shí),equals()方法也可能不等。

          public static void main(String args[]){

          String s1=new String("zhaoxudong"); //此語句創(chuàng)建了兩個(gè)對(duì)象,一個(gè)是字符串對(duì)象“zhaoxudong”(存放于棧中的字面量),另一個(gè)是new后在堆中產(chǎn)生的對(duì)象。詳細(xì)見下面的四.4

          String s2=new String("zhaoxudong");

          //上述兩條語句一共是產(chǎn)生了三個(gè)對(duì)象,因?yàn)闂V兄挥挟a(chǎn)生了一個(gè)對(duì)象。

          System.out.println(s1==s2);//false

          System.out.println(s1.equals(s2));//true

          System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode() ,指向同一內(nèi)存的引用

          System.out.println(s2.hashCode()); //equals和hashCode方法只用于兩個(gè)對(duì)象的比較和容器中,與對(duì)象的創(chuàng)建沒有關(guān)系

          Set hashset=new HashSet();

          hashset.add(s1);

          hashset.add(s2); /*在添加s1,s2時(shí), hashset認(rèn)為s1和s2是相等的,所以讓s2覆蓋了s1;*/

          Iterator it=hashset.iterator();

                      while(it.hasNext()){

                       System.out.println(it.next());

                      } //最后在while循環(huán)的時(shí)候只打印出了一個(gè)”zhaoxudong”。

          這是因?yàn)镾tring類已經(jīng)重寫了equals()方法和hashcode()方法。

          但是看下面的程序:

          public class HashSetTest {

             public static void main(String[] args)   {

                           HashSet hs=new HashSet();

                           hs.add(new Student(1,"zhangsan"));

                           hs.add(new Student(2,"lisi"));

                           hs.add(new Student(3,"wangwu"));

                           hs.add(new Student(1,"zhangsan"));

                           Iterator it=hs.iterator();

                           while(it.hasNext()){

                                  System.out.println(it.next());

                           } } }

          class Student {

               int num;

               String name;

               Student(int num,String name) {

                          this.num=num;

                           this.name=name; }

               public String toString() { return num+":"+name; }

                     }     

          輸出結(jié)果為:

                             1:zhangsan

                             1:zhangsan

                             3:wangwu

                             2:lisi

          問題出現(xiàn)了,為什么hashset添加了相等的元素呢,這是不是和hashset的原則違背了呢?回答是:沒有因?yàn)樵诟鶕?jù)hashcode()對(duì)兩次建立的new Student(1,"zhangsan")對(duì)象進(jìn)行比較時(shí),生成的是不同的哈希碼值,所以hashset把他當(dāng)作不同的對(duì)象對(duì)待了,當(dāng)然此時(shí)的equals()方法返回的值也不等。那么為什么會(huì)生成不同的哈希碼值呢?原因就在于我們自己寫的Student類并沒有重新自己的hashcode()和equals()方法,所以在比較時(shí),是繼承的object類中的hashcode()方法,它是一個(gè)本地方法,比較的是對(duì)象的地址(引用地址),使用new方法創(chuàng)建對(duì)象,兩次生成的當(dāng)然是不同的對(duì)象了,造成的結(jié)果就是兩個(gè)對(duì)象的hashcode()返回的值不一樣。那么怎么解決這個(gè)問題呢??

          答案是:在Student類中重新hashcode()和equals()方法。

          例如:

          class Student{

          int num;

          String name;

          Student(int num,String name){

                      this.num=num;

                      this.name=name; }

          public int hashCode(){ //重寫hashCode的方法

                      return num*name.hashCode(); }

          public boolean equals(Object o) {

                      Student s=(Student)o;

                      return num==s.num && name.equals(s.name); //&&的優(yōu)先級(jí)比==低,所以前面不必加括號(hào)

          }

          public String toString(){return num+":"+name; }

          }

          根據(jù)重寫的方法,即便兩次調(diào)用了new Student(1,"zhangsan"),我們?cè)讷@得對(duì)象的哈希碼時(shí),根據(jù)重寫的方法hashcode(),獲得的哈希碼肯定是一樣的。所以運(yùn)行修改后的程序時(shí),我們會(huì)看到重復(fù)元素的問題已經(jīng)消除。

          在hibernate的pojo類中,經(jīng)常使用set集合來保存相關(guān)對(duì)象,而set集合是不允許重復(fù)的。所以需要重寫equals和hashCode()方法。

          比如可以這樣寫:

          public int hashCode(){

             return 1;}//等價(jià)于hashcode無效

          這樣做的效果就是在比較哈希碼的時(shí)候不能進(jìn)行判斷,因?yàn)槊總€(gè)對(duì)象返回的哈希碼都是1,每次都必須要經(jīng)過比較equals()方法后才能進(jìn)行判斷是否重復(fù),這當(dāng)然會(huì)引起效率的大大降低。

           

          本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/elia1208/archive/2009/10/12/4657644.aspx

          posted on 2009-10-14 17:41 李云澤 閱讀(2770) 評(píng)論(0)  編輯  收藏 所屬分類: 面試筆試相關(guān)的

          主站蜘蛛池模板: 临夏市| 石阡县| 如东县| 许昌县| 吉木萨尔县| 汉阴县| 富源县| 迁西县| 溧阳市| 沐川县| 淮北市| 遂平县| 南漳县| 汉源县| 全州县| 曲阜市| 岑溪市| 新化县| 吴江市| 赤城县| 麟游县| 达日县| 云安县| 新建县| 克拉玛依市| 开远市| 郎溪县| 宁武县| 丽江市| 吉林市| 临湘市| 阿城市| 镇坪县| 东台市| 通山县| 雷山县| 崇礼县| 蒙阴县| 会昌县| 全南县| 平顶山市|