<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    細心!用心!耐心!

    吾非文人,乃市井一俗人也,讀百卷書,跨江河千里,故申城一游; 一兩滴辛酸,三四年學業,五六點粗墨,七八筆買賣,九十道人情。

    BlogJava 聯系 聚合 管理
      1 Posts :: 196 Stories :: 10 Comments :: 0 Trackbacks
    1. 首先equals()和hashcode()這兩個方法都是從object類中繼承過來的。
    equals()方法在object類中定義如下:
      public boolean equals(Object obj) {
    return (this == obj);
    }
    很明顯是對兩個對象的地址值進行的比較(即比較引用是否相同)。但是我們必需清楚,當String 、Math、還有Integer、Double。。。。等這些封裝類在使用equals()方法時,已經覆蓋了object類的equals()方法。比如在String類中如下:
      public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
    char v1[] = value;
    char v2[] = anotherString.value;
    int i = offset;
    int j = anotherString.offset;
    while (n-- != 0) {
        if (v1[i++] != v2[j++])
    return false;
    }
    return true;
        }
    }
    return false;
    }
    很明顯,這是進行的內容比較,而已經不再是地址的比較。依次類推Double、Integer、Math。。。。等等這些類都是重寫了equals()方法的,從而進行的是內容的比較。當然了基本類型是進行值的比較,這個沒有什么好說的。
    我們還應該注意,Java語言對equals()的要求如下,這些要求是必須遵循的:
    • 對稱性:如果x.equals(y)返回是“true”,那么y.equals(x)也應該返回是“true”。
    • 反射性:x.equals(x)必須返回是“true”。
    • 類推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也應該返回是“true”。
    • 還有一致性:如果x.equals(y)返回是“true”,只要x和y內容一直不變,不管你重復x.equals(y)多少次,返回都是“true”。
    • 任何情況下,x.equals(null),永遠返回是“false”;x.equals(和x不同類型的對象)永遠返回是“false”。
    以上這五點是重寫equals()方法時,必須遵守的準則,如果違反會出現意想不到的結果,請大家一定要遵守。
    2. 其次是hashcode() 方法,在object類中定義如下:
      public native int hashCode();
    說明是一個本地方法,它的實現是根據本地機器相關的。當然我們可以在自己寫的類中覆蓋hashcode()方法,比如String、Integer、Double。。。。等等這些類都是覆蓋了hashcode()方法的。例如在String類中定義的hashcode()方法如下:
        public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

                for (int i = 0; i < len; i++) {
                    h = 31*h + val[off++];
                }
                hash = h;
            }
            return h;
    }
    解釋一下這個程序(String的API中寫到):
    s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
    使用 int 算法,這里 s[i] 是字符串的第 i 個字符,n 是字符串的長度,^ 表示求冪。(空字符串的哈希碼為 0。)

    3.這里我們首先要明白一個問題:
    equals()相等的兩個對象,hashcode()一定相等;
    equals()不相等的兩個對象,卻并不能證明他們的hashcode()不相等。換句話說,equals()方法不相等的兩個對象,hashcode()有可能相等。(我的理解是由于哈希碼在生成的時候產生沖突造成的)。
    反過來:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。解釋下第3點的使用范圍,我的理解是在object、String等類中都能使用。在object類中,hashcode()方法是本地方法,返回的是對象的地址值,而object類中的equals()方法比較的也是兩個對象的地址值,如果equals()相等,說明兩個對象地址值也相等,當然hashcode()也就相等了;在String類中,equals()返回的是兩個對象內容的比較,當兩個對象內容相等時,
    Hashcode()方法根據String類的重寫(第2點里面已經分析了)代碼的分析,也可知道hashcode()返回結果也會相等。以此類推,可以知道Integer、Double等封裝類中經過重寫的equals()和hashcode()方法也同樣適合于這個原則。當然沒有經過重寫的類,在繼承了object類的equals()和hashcode()方法后,也會遵守這個原則。

    4.談到hashcode()和equals()就不能不說到hashset,hashmap,hashtable中的使用,具體是怎樣呢,請看如下分析:
    Hashset是繼承Set接口,Set接口又實現Collection接口,這是層次關系。那么hashset是根據什么原理來存取對象的呢?
    在hashset中不允許出現重復對象,元素的位置也是不確定的。在hashset中又是怎樣判定元素是否重復的呢?這就是問題的關鍵所在,經過一下午的查詢求證終于獲得了一點啟示,和大家分享一下,在java的集合中,判斷兩個對象是否相等的規則是:
    1),判斷兩個對象的hashCode是否相等
          如果不相等,認為兩個對象也不相等,完畢
          如果相等,轉入2)
    (這一點只是為了提高存儲效率而要求的,其實理論上沒有也可以,但如果沒有,實際使用時效率會大大降低,所以我們這里將其做為必需的。后面會重點講到這個問題。)
    2),判斷兩個對象用equals運算是否相等
          如果不相等,認為兩個對象也不相等
          如果相等,認為兩個對象相等(equals()是判斷兩個對象是否相等的關鍵)
    為什么是兩條準則,難道用第一條不行嗎?不行,因為前面已經說了,hashcode()相等時,equals()方法也可能不等,所以必須用第2條準則進行限制,才能保證加入的為非重復元素。
    比如下面的代碼:

    public static void main(String args[]){
    String s1=new String("zhaoxudong");
    String s2=new String("zhaoxudong");
    System.out.println(s1==s2);//false
    System.out.println(s1.equals(s2));//true
    System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode()
    System.out.println(s2.hashCode());
    Set hashset=new HashSet();
    hashset.add(s1);
    hashset.add(s2);
    /*實質上在添加s1,s2時,運用上面說到的兩點準則,可以知道hashset認為s1和s2是相等的,是在添加重復元素,所以讓s2覆蓋了s1;*/
    Iterator it=hashset.iterator();
                while(it.hasNext())
                {
                 System.out.println(it.next());
                }
    最后在while循環的時候只打印出了一個”zhaoxudong”。
    輸出結果為:false
                true
                -967303459
                -967303459
    這是因為String類已經重寫了equals()方法和hashcode()方法,所以在根據上面的第1.2條原則判定時,hashset認為它們是相等的對象,進行了重復添加。
    但是看下面的程序:
    import java.util.*;
    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;
                     }
               }     
    輸出結果為:
                          1:zhangsan
                       1:zhangsan
                       3:wangwu
                       2:lisi
    問題出現了,為什么hashset添加了相等的元素呢,這是不是和hashset的原則違背了呢?回答是:沒有
    因為在根據hashcode()對兩次建立的new Student(1,"zhangsan")對象進行比較時,生成的是不同的哈希碼值,所以hashset把他當作不同的對象對待了,當然此時的equals()方法返回的值也不等(這個不用解釋了吧)。那么為什么會生成不同的哈希碼值呢?上面我們在比較s1和s2的時候不是生成了同樣的哈希碼嗎?原因就在于我們自己寫的Student類并沒有重新自己的hashcode()和equals()方法,所以在比較時,是繼承的object類中的hashcode()方法,呵呵,各位還記得object類中的hashcode()方法比較的是什么吧??!
    它是一個本地方法,比較的是對象的地址(引用地址),使用new方法創建對象,兩次生成的當然是不同的對象了(這個大家都能理解吧。。。),造成的結果就是兩個對象的hashcode()返回的值不一樣。所以根據第一個準則,hashset會把它們當作不同的對象對待,自然也用不著第二個準則進行判定了。那么怎么解決這個問題呢??
    答案是:在Student類中重新hashcode()和equals()方法。
    例如:
      class Student
    {
    int num;
    String name;
    Student(int num,String name)
    {
                this.num=num;
                this.name=name;
    }
    public int hashCode()
    {
                return num*name.hashCode();
    }
    public boolean equals(Object o)
    {
                Student s=(Student)o;
                return num==s.num && name.equals(s.name);
    }
    public String toString()
    {
                return num+":"+name;
    }
    }
    根據重寫的方法,即便兩次調用了new Student(1,"zhangsan"),我們在獲得對象的哈希碼時,根據重寫的方法hashcode(),獲得的哈希碼肯定是一樣的(這一點應該沒有疑問吧)。
    當然根據equals()方法我們也可判斷是相同的。所以在向hashset集合中添加時把它們當作重復元素看待了。所以運行修改后的程序時,我們會發現運行結果是:
                          1:zhangsan
                       3:wangwu
                       2:lisi
    可以看到重復元素的問題已經消除。
    關于在hibernate的pojo類中,重新equals()和hashcode()的問題:
    1),重點是equals,重寫hashCode只是技術要求(為了提高效率)
    2),為什么要重寫equals呢,因為在java的集合框架中,是通過equals來判斷兩個對象是否相等的
    3),在hibernate中,經常使用set集合來保存相關對象,而set集合是不允許重復的。我們再來談談前面提到在向hashset集合中添加元素時,怎樣判斷對象是否相同的準則,前面說了兩條,其實只要重寫equals()這一條也可以。
    但當hashset中元素比較多時,或者是重寫的equals()方法比較復雜時,我們只用equals()方法進行比較判斷,效率也會非常低,所以引入了hashcode()這個方法,只是為了提高效率,但是我覺得這是非常有必要的(所以我們在前面以兩條準則來進行hashset的元素是否重復的判斷)。
    比如可以這樣寫:
    public int hashCode(){
       return  1;}//等價于hashcode無效
    這樣做的效果就是在比較哈希碼的時候不能進行判斷,因為每個對象返回的哈希碼都是1,每次都必須要經過比較equals()方法后才能進行判斷是否重復,這當然會引起效率的大大降低。
    我有一個問題,如果像前面提到的在hashset中判斷元素是否重復的必要方法是equals()方法(根據網上找到的觀點),但是這里并沒有涉及到關于哈希表的問題,可是這個集合卻叫hashset,這是為什么??
    我想,在hashmap,hashtable中的存儲操作,依然遵守上面的準則。所以這里不再多說。這些是今天看書,網上查詢資料,自己總結出來的,部分代碼和語言是引述,但是千真萬確是自己總結出來的。有錯誤之處和不詳細不清楚的地方還請大家指出,我也是初學者,所以難免會有錯誤的地方,希望大家共同討論。
    posted on 2012-10-11 10:06 張金鵬 閱讀(126) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 最新亚洲春色Av无码专区| 亚洲另类春色国产精品| 鲁啊鲁在线视频免费播放| 好爽…又高潮了免费毛片| 色噜噜亚洲男人的天堂| 一二三四在线播放免费观看中文版视频 | 亚洲AV无码乱码在线观看裸奔| 成年免费大片黄在线观看com| 天堂亚洲免费视频| 免费激情网站国产高清第一页| 亚洲精品无码99在线观看| 特a级免费高清黄色片| 亚洲综合av永久无码精品一区二区| 久久九九免费高清视频| 亚洲av色影在线| 国产福利视精品永久免费 | 亚洲成av人片在线天堂无| 日本一道本高清免费| 一本一道dvd在线观看免费视频 | 7777久久亚洲中文字幕| 成**人免费一级毛片| 美女又黄又免费的视频| 在线观看午夜亚洲一区| 99re在线视频免费观看| 亚洲欧美自偷自拍另类视| 无码专区一va亚洲v专区在线| a毛片成人免费全部播放| 亚洲第一网站免费视频| 国产又黄又爽又刺激的免费网址| 免费国产污网站在线观看不要卡| 人人狠狠综合久久亚洲88| 免费观看激色视频网站bd | 日韩高清在线免费看| 一级一黄在线观看视频免费| 久久久亚洲精品国产| 暖暖免费高清日本中文| 久久国产精品免费视频| 亚洲日韩AV一区二区三区中文 | 99爱在线精品免费观看| 美女视频黄a视频全免费网站一区 美女视频黄a视频全免费网站色 | 成年女人毛片免费观看97|