日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

hashcode() and equals()用法。

 昵稱9290112 2012-03-23

以下內(nèi)容參見了如下網(wǎng)址:

1、http://blog.csdn.net/ngqzmjmj/archive/2005/04/27/365149.aspx

2、http://blog.csdn.net/pbnow/archive/2006/04/25/677253.aspx

3、http://blog.csdn.net/petercheng456/archive/2005/08/02/444427.aspx

講到Hashtable和HashMap的區(qū)別的時候,就不得不說說hashCode的問題,下面是自己從網(wǎng)上找到的幾篇資料,自己結(jié)合HashTable來整理了一下:
1、任何class如果覆寫了equals()方法,就必須覆寫hashCode()。
這樣作的目的就是為了你的類就能夠很好的與java的集合框架協(xié)同工作。如果我們能夠確認(rèn)我們定義的類不會和java集合類產(chǎn)生關(guān)系,那么我們完全沒有必要在覆寫equals()方法的時候覆寫hashCode。

2、關(guān)于Hashtable,判斷key是否相同的條件是:hashCode()相同 && 滿足equals()。這兩個方法都是可以重構(gòu)的,所以Hashtable沒有用==,給了程序員實(shí)現(xiàn)自己的Hashtable的好的途徑,的確Sun想得很嚴(yán)密。

例子1:
      class a{
            private int b;  
            public a(int c){//構(gòu)造函數(shù)
             b=c;
          }
      public String eqals(Object o){
       if(this==o) return true;
        if(o instanceof a){
         return a.b==(a)o.b; 
        }
        return false;
              }
      public static void main(String[] args){
       Map p=new HashMap();
       p.put(new a(1));   
       p.get(new a(1))
       /*這里返回為null,因?yàn)閙ap是根據(jù)equals()和hashCode()來判斷對象是否相等,所以在類里覆寫了equals(),就一定要覆寫hashCode()。關(guān)于Hashtable,判斷key是否相同的條件是:hashCode()相同 && 滿足equals(),而一個類如果沒有覆寫equals()方法,那么這個類的equals方法比較的是對象的內(nèi)存地址。如果沒有覆寫HashCode,那么該類的hashCode是通過對象的內(nèi)存地址轉(zhuǎn)換而來.
       */
         }
       }
       例子二:
       /**
* 類:TestStudent
*/
        public class TestStudent {
         private int age;

         public TestStudent(int age) {
             this.age = age;
         }

         public TestStudent() {
         }

         public boolean equals(Object o) {
//            if (this == o) return true;
//            if (o == null || getClass() != o.getClass()) return false;
//
//            final TestStudent that = (TestStudent) o;
//
//            if (age != that.age) return false;

             return true;
         }

         public int hashCode() {
             return age;
         }
}
/**
* 類:TestTeacher
*/
public class TestTeacher {
         private int age;

         public TestTeacher(int age) {
             this.age = age;
         }

         public TestTeacher() {
         }

         public boolean equals(Object o) {
//            if (this == o) return true;
//            if (o == null || getClass() != o.getClass()) return false;
//
//            final TestTeacher that = (TestTeacher) o;
//
//            if (age != that.age) return false;
//
//            return true;
             return true;
         }

         public int hashCode() {
             return age;
         }
}

public class TestHashtable2 {
         public static void main(String[] args){
             Hashtable table=new Hashtable();
             table.put(new TestTeacher(1),"aaa");
             System.out.print("=========="+table.get(new TestStudent(1)));
         }
}
輸出結(jié)果是:==========aaa
從上面這個例子就可以看出來Hashtable中key和對象所屬的class無關(guān),只和equals方法和hashCode方法的有關(guān)。當(dāng)然正常情況下我們覆寫equals方法的時候下面兩句話是必不可少的。
if (this == o) return true;//保證了統(tǒng)一對對象的絕對一致性。
if (o == null || getClass() != o.getClass()) return false;
final TestStudent that = (TestStudent) o;//保證了只有同一個類的不同對象進(jìn)行equals,雖然上面的例子可以進(jìn)行equals對比不同的對象,但是實(shí)際情況中不同對象間的equals進(jìn)行對比意義不大。
if (age != that.age){
     return false;
}

3、在程序執(zhí)行期間,同一個對象調(diào)用hashCode()必須返回同一個值(同一個應(yīng)用執(zhí)行期)
4、如果兩個對象equals,那么他們的hashCode()必須相等。(個人感覺這個要求也是為了和java的結(jié)合框架協(xié)同工作,因?yàn)槲覀冏约憾x的類完全可以覆寫equals方法,但是不覆寫hashCode,盡管我們可以這樣做,但是這樣做是不合理的,他會為我們的程序埋下錯誤隱患。雖然java沒有從在編譯器對上面的說法進(jìn)行控制,但是上面的說法是我們在設(shè)計(jì)類的時候應(yīng)該遵循的規(guī)則)。
5、如果兩個對象equals不相等,那么他們的hashCode()不必產(chǎn)生不同的結(jié)果(上面的例2就可以說明問題),程序員應(yīng)該注意到,對不同的對象產(chǎn)生不同的hashCode(),有可能提升 hash table(哈希表)的效率
7、Map.put(key,value)時根據(jù)key.hashCode生成一個內(nèi)部hash值,根據(jù)這個hash值將對象存放在一個table中。Map.get(key)會比較key.hashCode和equals方法,當(dāng)且僅當(dāng)這兩者相等時,才能正確定位到table;java中Set是通過Map實(shí)現(xiàn)的,所以Map和Set的所有實(shí)現(xiàn)類都要注意這一點(diǎn).

8、
StringBuffer buffer = new StringBuffer();
buffer.append("some");
String a = buffer.toString();
String b = "some";

現(xiàn)在有三個式子,結(jié)果在后面用注釋的形式標(biāo)出:

a.equals(b);//true
a==b;//false
a.hashCode()==b.hashCode();//true

說明:"ab"=="ab"是因?yàn)榫幾g的時候就把這兩個指向同一個常量了,屬于編譯優(yōu)化的一部分。但是動態(tài)生成的字符串的地址就不一樣了。比如String a = buffer.toString(), 但是buffer.append("some")和String b = "some"里兩個"some"常量應(yīng)當(dāng)是指向同一個地址。

9、如果想判斷是否兩個對象引用指向同一個實(shí)體,唯一的正確途徑是使用==,因?yàn)橹挥兴粫恢貥?gòu),要慎用hashCode

10、有一點(diǎn)我們應(yīng)該是能夠確認(rèn)的,就是同樣的數(shù)字轉(zhuǎn)換成hashCode后的值肯定一樣,因此我們在覆寫hashCode時候應(yīng)該利用自己編寫的類獨(dú)特屬性進(jìn)行hashCode運(yùn)算(當(dāng)然不僅僅是一個屬性,可以是多個屬性),這樣我們就可以盡量的保證每個類對象的具有不同的hashCode,如果這些不同的對象有機(jī)會進(jìn)入同一個map的時候就可以保證其hashCode不一樣,從而提高map的檢索。(下面文章中提到了,在一個map中的對象應(yīng)該盡量的避免其hashCode一樣)。

11、關(guān)于hashCode的常規(guī)寫法:把所有屬性都參與散列,通常的算法就是將不同的質(zhì)數(shù)與字段做乘積和,比如一個類具有兩個屬性age和name,那么return    11*age+13*name;。至于為什么用質(zhì)數(shù)的問題個人就沒有深入研究了。對于我們對算法要求不是很高的我們當(dāng)然可以讓所有屬性都參與散列,但是如果我們?yōu)榱俗非笠稽c(diǎn)效率,那么我覺的應(yīng)該只將類的獨(dú)特字段進(jìn)行散列就可以了。

12、另外一點(diǎn)就是充分利用IDE,剛開始看這個問題的時候,只知道覆寫了equals就應(yīng)該覆寫hashCode,但是hashCode該怎么寫,自己也不是很清楚,通過自己的IDE,Intellij IDEA自動生成的hashCode,就了解到了將類的所有屬性都參與散列的方法,個人覺的,IDE給出的算法雖然不是針對某個類最優(yōu)的算法,但是對于我們一般的應(yīng)用程序,對算法要求不高的程序,還是很有參考價值的。

 

以下內(nèi)容是轉(zhuǎn)帖http://dev2dev./bbsdoc/20060807307.html

為什么HashCode對于對象是如此的重要?

  一個對象的HashCode就是一個簡單的Hash算法的實(shí)現(xiàn),雖然它和那些真正的復(fù)雜的Hash算法相比還不能叫真正的算法,它如何實(shí)現(xiàn)它,不僅僅是程序員的編程水平問題,而是關(guān)系到你的對象在存取是性能的非常重要的關(guān)系.有可能,不同的HashCode可能會使你的對象存取產(chǎn)生,成百上千倍的性能差別。

  我們先來看一下,在JAVA中兩個重要的數(shù)據(jù)結(jié)構(gòu):HashMap和Hashtable,雖然它們有很大的區(qū)別,如繼承關(guān)系不同,對value的約束條件(是否允許null)不同,以及線程安全性等有著特定的區(qū)別,但從實(shí)現(xiàn)原理上來說,它們是一致的.所以,我們只以Hashtable來說明:

  在java中,存取數(shù)據(jù)的性能,一般來說當(dāng)然是首推數(shù)組,但是在數(shù)據(jù)量稍大的容器選擇中,Hashtable將有比數(shù)組性能更高的查詢速度.具體原因看下面的內(nèi)容。

  Hashtable在存儲數(shù)據(jù)時,一般先將作為key的對象的HashCode和0x7FFFFFFF做與操作,因?yàn)橐粋€對象的HashCode可以為負(fù)數(shù),這樣操作后可以保證它為一個正整數(shù).然后以Hashtable的長度取模,得到值對象在Hashtable中的索引。

  index = (o.hashCode() & 0x7FFFFFFF)%hs.length;這個值對象就會直接放在Hashtable的第index位置,對于寫入,這和數(shù)組一樣,把一個對象放在其中的第index位置,但如果是查詢,經(jīng)過同樣的算法,Hashtable可以直接通過key得到index,從第index取得這個值對象,而數(shù)組卻要做循環(huán)比較.所以對于數(shù)據(jù)量稍大時,Hashtable的查詢比數(shù)據(jù)具有更高的性能。

  雖然不同對象有不同的hashcode,但不同的hashCode經(jīng)過與長度的取余,就很可能產(chǎn)生相同的index。

  極端情況下會有大量的對象產(chǎn)生一個相同的索引.這就是關(guān)系Hashtable性能問題的最重要的問題:

  Hash沖突。

  常見的Hash沖突是不同key對象最終產(chǎn)生了相同的索引,而一種非常甚至絕對少見的Hash沖突是,如果一組對象的個數(shù)大過了int范圍,而HashCode的長度只能在int范圍中,所以肯定要有同一組的元素有相同的HashCode,這樣無論如何他們都會有相同的索引.當(dāng)然這種極端的情況是極少見的,可以暫不考慮,但是對于同的HashCode經(jīng)過取模,則會產(chǎn)中相同的索引,或者不同的對象卻具有相同的HashCode,當(dāng)然具有相同的索引。

  事實(shí)上一個設(shè)計(jì)各好的HashTable,一般來說會比較平均地分布每個元素,因?yàn)镠ashtable的長度總是比實(shí)際元素的個數(shù)按一定比例進(jìn)行自增(裝填因子一般為0.75)左右,這樣大多數(shù)的索引位置只有一個對象,而很少的位置會有幾個元素.所以Hashtable中的每個位置存放的是一個鏈表,對于只有一個對象是位置,鏈表只有一個首節(jié)點(diǎn)(Entry),Entry的next為null.然后有hashCode,key,value屬性保存了該位置的對象的HashCode,key和value(對象本身),如果有相同索引的對象進(jìn)來則會進(jìn)入鏈表的下一個節(jié)點(diǎn).如果同一個索引中有多個對象,根據(jù)HashCode和key可以在該鏈表中找到一個和查詢的key相匹配的對象。

  從上面我看可以看到,對于HashMap和Hashtable的存取性能有重大影響的首先是應(yīng)該使該數(shù)據(jù)結(jié)構(gòu)中的元素盡量大可能具有不同的HashCode,雖然這并不能保證不同的HashCode產(chǎn)生不同的index,但相同的HashCode一定產(chǎn)生相同的index,從而影響產(chǎn)生Hash沖突。

  對于一個象,如果具有很多屬性,把所有屬性都參與散列,顯然是一種笨拙的設(shè)計(jì).因?yàn)閷ο蟮腍ashCode()方法幾乎無所不在地被自動調(diào)用,如equals比較,如果太多的對象參與了散列.那么需要的操作常數(shù)時間將會增加很大.所以,挑選哪些屬性參與散列絕對是一個編程水平的問題。

  從實(shí)現(xiàn)來說,一般的HashCode方法會這樣:

  return Attribute1.HashCode() + Attribute1.HashCode()..[+super.HashCode()]。

  我們知道,每次調(diào)用這個方法,都要重新對方法內(nèi)的參與散列的對象重新計(jì)算一次它們的HashCode的運(yùn)算,如果一個對象的屬性沒有改變,仍然要每次都進(jìn)行計(jì)算,所以如果設(shè)置一個標(biāo)記來緩存當(dāng)前的散列碼,只要當(dāng)參與散列的對象改變時才重新計(jì)算,否則調(diào)用緩存的hashCode,這可以從很大程度上提高性能。

  默認(rèn)的實(shí)現(xiàn)是將對象內(nèi)部地址轉(zhuǎn)化為整數(shù)作為HashCode,這當(dāng)然能保證每個對象具有不同的HasCode,因?yàn)椴煌膶ο髢?nèi)部地址肯定不同(廢話),但java語言并不能讓程序員獲取對象內(nèi)部地址,所以,讓每個對象產(chǎn)生不同的HashCode有著很多可研究的技術(shù)。

  如果從多個屬性中采樣出能具有平均分布的hashCode的屬性,這是一個性能和多樣性相矛盾的地方,如果所有屬性都參與散列,當(dāng)然hashCode的多樣性將大大提高,但犧牲了性能,而如果只能少量的屬性采樣散列,極端情況會產(chǎn)生大量的散列沖突,如對"人"的屬性中,如果用性別而不是姓名或出生日期,那將只有兩個或幾個可選的hashcode值,將產(chǎn)生一半以上的散列沖突.所以如果可能的條件下,專門產(chǎn)生一個序列用來生成HashCode將是一個好的選擇(當(dāng)然產(chǎn)生序列的性能要比所有屬性參與散列的性能高的情況下才行,否則還不如直接用所有屬性散列)。

  如何對HashCode的性能和多樣性求得一個平衡,可以參考相關(guān)算法設(shè)計(jì)的書,其實(shí)并

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多