国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
對(duì)java中equals和hashCode函數(shù)的一些理解
JDK的java.lang.Object類(lèi)中實(shí)現(xiàn)了equals函數(shù),其定義說(shuō)明如下:
引用

    public boolean equals(Object obj)
         Indicates whether some other object is "equal to" this one.
         The equals method implements an equivalence relation on non-null object references:
          [list=5]
         
  • It  is reflexive: for any non-null reference value x, x.equals(x) should return true.             
  •          
  • It  is symmetric: for any non-null reference valuesx and y, x.equals(y) should return true if and only if y.equals(x)returns true.
  •          
  • It  is transitive: for any non-null referencevalues x, y, and z, if x.equals(y) returns true and y.equals(z) returnstrue, then x.equals(z) should return true.
  •          
  • It  is consistent: for any non-null referencevalues x and y, multiple invocations of x.equals(y) consistently returntrue or consistently return false, provided no information used inequals comparisons on the objects is modified.
  •          
  • For  any non-null reference value x, x.equals(null) should return false.
  •           [/list]
             The equals method for class Object implements the mostdiscriminating possible equivalence relation on objects; that is, forany non-null reference values x and y, this method returns true if andonly if x and y refer to the same object (x == y has the value true).
             Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.


    其具體的實(shí)現(xiàn)代碼如下所示:
    Java代碼
    1. public boolean equals(Object obj) {  
    2.     return (this == obj);  
    3. }    

         從上面的代碼中可以看出,Object類(lèi)的equals實(shí)現(xiàn)只是簡(jiǎn)單地調(diào)用了“==”運(yùn)算符,也即定義中說(shuō)明的,對(duì)于兩個(gè)非空對(duì)象X和Y,有且僅當(dāng)X和Y指向同一個(gè)對(duì)象時(shí)該函數(shù)才返回true。由于Object類(lèi)是java中所有類(lèi)的超類(lèi),因而其它任何類(lèi)都默認(rèn)繼承了此函數(shù)。在大多數(shù)情況下,此默認(rèn)的實(shí)現(xiàn)方式是合適的,因?yàn)槿我粋€(gè)類(lèi)本質(zhì)上都是唯一的;但是對(duì)于那些表示“值”的類(lèi)(如Integer、String等),它們引入了自己特有的“邏輯相等”的概念,此時(shí)就必須修改equals函數(shù)的實(shí)現(xiàn)。
    例如java.lang.String類(lèi)的實(shí)現(xiàn)如下:
    Java代碼
    1.    public boolean equals(Object anObject) {  
    2.        if (this == anObject) {  
    3.     return true;  
    4. }  
    5. if (anObject instanceof String) {  
    6.     String anotherString = (String)anObject;  
    7.     int n = count;  
    8.     if (n == anotherString.count) {  
    9.     char v1[] = value;  
    10.     char v2[] = anotherString.value;  
    11.     int i = offset;  
    12.     int j = anotherString.offset;  
    13.     while (n-- != 0) {  
    14.         if (v1[i++] != v2[j++])  
    15.         return false;  
    16.     }  
    17.     return true;  
    18.     }  
    19. }  
    20. return false;  
    21.    }  

    java.lang.Integer類(lèi)的實(shí)現(xiàn)如下:
    Java代碼
    1. public boolean equals(Object obj) {  
    2.     if (obj instanceof Integer) {  
    3.         return value == ((Integer)obj).intValue();  
    4.     }  
    5.     return false;  
    6.     }  

          String類(lèi)的equals實(shí)現(xiàn)使得當(dāng)兩個(gè)String對(duì)象所表示的字符串的值是一樣的時(shí)候就能返回true;而Integer類(lèi)則當(dāng)兩個(gè)Integer對(duì)象所持有的整數(shù)值是一樣的時(shí)候就能返回true。
         因此,當(dāng)我們我們自己編寫(xiě)的類(lèi)需要引入“邏輯相等”的概念,且其超類(lèi)又沒(méi)有改寫(xiě)equals的實(shí)現(xiàn)時(shí),我們就必須實(shí)現(xiàn)自己的equals函數(shù)。在上面Object類(lèi)中關(guān)于equals函數(shù)的說(shuō)明中,定義了5條改寫(xiě)equals函數(shù)所必須遵守的規(guī)范。其中第1條自反性(reflexivity)和第5條通常能夠自行滿足。下面我們重點(diǎn)介紹下第2點(diǎn)對(duì)稱性(symmetric)、第3點(diǎn)傳遞性(transitive)和第4點(diǎn)一致性(consistent)。
          對(duì)稱性
    即對(duì)于任意兩個(gè)引用值X和Y,X.equals(Y) 和 Y.equals(X) 返回的結(jié)果必須是一致的。下面引用《effect java》上的例子來(lái)說(shuō)明了違反這一特性的后果:
    Java代碼
    1. public class CaseInsensitiveString {  
    2.       
    3.     private String s;  
    4.       
    5.     public boolean equals(Object obj){  
    6.         if(obj instanceof CaseInsensitiveString)  
    7.             return s.equalsIgnoreCase(((CaseInsensitiveString)obj).s);  
    8.         if(obj instanceof String)  
    9.             return s.equalsIgnoreCase((String)obj);  
    10.         return false;  
    11.     }  
    12. }  

    然后我們定義如下的類(lèi)來(lái)進(jìn)行測(cè)試:
    Java代碼
    1. public void test(){  
    2.     CaseInsensitiveString cis = new CaseInsensitiveString("Value");  
    3.     String s = "Value";  
    4.     List list = new ArrayList();  
    5.     list.add(cis);  
    6.     System.out.println(cis.equals(s));  
    7.     System.out.println(s.equals(cis));  
    8.     System.out.println(list.contains(s));  
    9. }  

    運(yùn)行test(),第一條語(yǔ)句的輸出為true,而后兩條為false。因?yàn)镃aseInsensitiveString類(lèi)中equals函數(shù)對(duì)String對(duì)象的比較也可能返回true,只要其大小寫(xiě)不敏感的字符串值相等;而在String類(lèi)中對(duì)任何非String對(duì)象都返回false,這樣CaseInsensitiveString的實(shí)現(xiàn)就違反了對(duì)稱性,從而導(dǎo)致了第三條語(yǔ)句也返回了意想不到的結(jié)果false。這是因?yàn)锳rrayList的contains函數(shù)實(shí)現(xiàn)是用實(shí)參s對(duì)list中每一個(gè)對(duì)象調(diào)用equals函數(shù),若有equals函數(shù)返回true,則contains返回true;因而在這里contains函數(shù)必然返回false。因此,如果違反了對(duì)稱性,則可能會(huì)得到意料之外的結(jié)果。解決此問(wèn)題的一個(gè)辦法就是在CaseInsensitiveString類(lèi)的equals函數(shù)中對(duì)Stirng對(duì)象的比較無(wú)論值是否一致都返回false。
          傳遞性
    即對(duì)于任意的引用值X、Y和Z,如果 X.equals(Y) 和 Y.equals(Z) 都返回true,則 X.equals(Z) 也一定返回true。下面舉例說(shuō)明:
    Java代碼
    1.  public class Point {  
    2.     private final int x;  
    3.   
    4.     private final int y;  
    5.   
    6.     public Point(int x, int y) {  
    7.         this.x = x;  
    8.         this.y = y;  
    9.     }  
    10.   
    11.     public boolean equals(Object obj) {  
    12.         if (!(obj instanceof Point))  
    13.             return false;  
    14.         Point p = (Point) obj;  
    15.         return p.x == x && p.y == y;  
    16.     }  
    17. }  
    18.   
    19. public class ColorPoint extends Point {  
    20.   
    21.     private int z;  
    22.   
    23.     public ColorPoint(int x, int y, int z) {  
    24.         super(x, y);  
    25.         this.z = z;  
    26.     }  
    27.   
    28.     public boolean equals(Object obj) {  
    29.         if (!(obj instanceof ColorPoint))  
    30.             return false;  
    31.         ColorPoint cp = (ColorPoint) obj;  
    32.         return super.equals(obj) && cp.z == this.z;  
    33.     }  
    34. }  

    在上面的代碼中定義了類(lèi)Point及其子類(lèi)ColorPoint,并分別改寫(xiě)了equals函數(shù)。下面運(yùn)行如下代碼來(lái)測(cè)試:
    Java代碼
    1. ColorPoint cp1 = new ColorPoint(1,2,3);  
    2. ColorPoint cp2 = new ColorPoint(1,2,4);  
    3. Point p = new Point(1,2);  
    4. System.out.println(cp1.equals(p));  
    5. System.out.println(p.equals(cp2));  
    6. System.out.println(cp1.equals(cp2));  

    結(jié)果前兩條語(yǔ)句輸出“true”,而最后一條語(yǔ)句輸出為“false”;從而違反了傳遞性規(guī)范。其主要原因是在基類(lèi)的equals函數(shù)中并未對(duì)子類(lèi)加以區(qū)分,從而使得基類(lèi)與子類(lèi)之間的比較也能返回true。要解決此方法,《effect java》上提供了“復(fù)合代替繼承”的方法;另外,如果可以將基類(lèi)和子類(lèi)視為不等的話,使用 getClass()函數(shù)代替 instanceof運(yùn)算符進(jìn)行比較可以很好的解決這一問(wèn)題。getClass()會(huì)返回此對(duì)象的運(yùn)行期類(lèi)(runtimeclass),因?yàn)榛?lèi)和子類(lèi)屬于不同的class,getClass()能夠?qū)⑵鋮^(qū)分開(kāi)來(lái)。下面是一段示例的代碼:
    Java代碼
    1. public boolean equals(Object obj) {  
    2.         if(obj.getClass() != this.getClass())  
    3.             return false;  
    4.         Point p = (Point) obj;  
    5.         return p.x == x && p.y == y;  
    6.           
    7.     }  

          一致性
    即如果兩個(gè)對(duì)象相等的話,那么它們必須始終保持相等,除非至少有一個(gè)對(duì)象被修改了。

    在Object類(lèi)equals函數(shù)的說(shuō)明中的最后一段提到當(dāng)我們改寫(xiě)equals函數(shù)的時(shí)候,通常都需要改寫(xiě)hashCode函數(shù),后者同樣在Object類(lèi)中進(jìn)行了定義,如下:
    引用

    public int hashCode()
    Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those provided by java.util.Hashtable.
    The general contract of hashCode is:
    [list=3]
  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCodemethod must consistently return the same integer, provided noinformation used in equals comparisons on the object is modified. Thisinteger need not remain consistent from one execution of an applicationto another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCodemethod on each of the two objects must produce distinct integerresults. However, the programmer should be aware that producingdistinct integer results for unequal objects may improve theperformance of hashtables.
  • [/list]
    As much as is reasonably practical, the hashCodemethod defined by class Object does return distinct integers fordistinct objects. (This is typically implemented by converting theinternal address of the object into an integer, but this implementationtechnique is not required by the JavaTM programming language.)

    hashCode()函數(shù)返回一個(gè)對(duì)象的散列值(hash code),在java中有些集合類(lèi)都是基于散列值的,如HashMap、HashSet、Hashtable等;它們都根據(jù)對(duì)象的散列值將其映射到相應(yīng)的散列桶中。如Hashtable的put和get函數(shù)的實(shí)現(xiàn)如下所示:
    Java代碼
    1.   public synchronized V get(Object key) {  
    2. Entry tab[] = table;  
    3. int hash = key.hashCode();  
    4. int index = (hash & 0x7FFFFFFF) % tab.length;  
    5. for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {  
    6.     if ((e.hash == hash) && e.key.equals(key)) {  
    7.     return e.value;  
    8.     }  
    9. }  
    10. return null;  
    11.    }  
    12.   
    13. ublic synchronized V put(K key, V value) {  
    14. // Make sure the value is not null  
    15. if (value == null) {  
    16.     throw new NullPointerException();  
    17. }  
    18.   
    19. // Makes sure the key is not already in the hashtable.  
    20. Entry tab[] = table;  
    21. int hash = key.hashCode();  
    22. int index = (hash & 0x7FFFFFFF) % tab.length;  
    23. for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {  
    24.     if ((e.hash == hash) && e.key.equals(key)) {  
    25.     V old = e.value;  
    26.     e.value = value;  
    27.     return old;  
    28.     }  
    29. }  
    30.   
    31. modCount++;  
    32. if (count >= threshold) {  
    33.     // Rehash the table if the threshold is exceeded  
    34.     rehash();  
    35.   
    36.            tab = table;  
    37.            index = (hash & 0x7FFFFFFF) % tab.length;  
    38. }   
    39.   
    40. // Creates the new entry.  
    41. Entry<K,V> e = tab[index];  
    42. tab[index] = new Entry<K,V>(hash, key, value, e);  
    43. count++;  
    44. return null;  
    45.    }  

    因而hashCode函數(shù)極大地影響了這些集合類(lèi)的正常工作。如果在改寫(xiě)完equals函數(shù)后,不相應(yīng)改寫(xiě)hashCode函數(shù),則可能會(huì)得不到想要的結(jié)果。如下例所示:
    Java代碼
    1. Point p1 = new Point(12);  
    2. Point p2 = new Point(12);  
    3. Hashtable<Point, String> ht = new Hashtable<Point, String>();  
    4. ht.put(p1, "value");  
    5. System.out.println(p1.equals(p2));  
    6. System.out.println(ht.get(p2));  

    由上面Point類(lèi)的實(shí)現(xiàn),p1和p2是相等的,第一個(gè)語(yǔ)句正常輸出true;但是第二個(gè)語(yǔ)句輸出的值是null,并沒(méi)有得到期望中的“value”。導(dǎo)致這一問(wèn)題的根本原因是Point類(lèi)改寫(xiě)了equals函數(shù),對(duì)相等的概念作了更改,但沒(méi)有相應(yīng)更改hashCode函數(shù),使得兩個(gè)相等的函數(shù)擁有不同的hashCode,違反了Object類(lèi)關(guān)于hashCode的約定中的第2點(diǎn),從而返回了錯(cuò)誤的結(jié)果。
    在Object類(lèi)中定義的幾個(gè)hashCode約定如下:
    1. 在同一應(yīng)用中,一個(gè)對(duì)象的hashCode函數(shù)在equals函數(shù)沒(méi)有更改的情況下,無(wú)論調(diào)用多少次,它都必須返回同一個(gè)整數(shù)。
    2. 兩個(gè)對(duì)象如果調(diào)用equals函數(shù)是相等的話,那么調(diào)用hashCode函數(shù)一定會(huì)返回相同的整數(shù)。
    3. 兩個(gè)對(duì)象如果調(diào)用equals函數(shù)是不相等的話,那么調(diào)用hashCode函數(shù)不要求一定返回不同的整數(shù)。
    我們?cè)诟膶?xiě)equals 和 hashCode 函數(shù)的時(shí)候,一定要遵守如上3條約定,在改寫(xiě)equals的同時(shí)也改寫(xiě)hashCode的實(shí)現(xiàn),這樣才能保證得到正確的結(jié)果。
    本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
    打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
    猜你喜歡
    類(lèi)似文章
    Hashcode的作用
    Java 理論與實(shí)踐: 哈希
    java中Object的默認(rèn)hashCode方法實(shí)現(xiàn)原理
    淺談Java中的hashcode方法
    Java中的equals和hashCode方法詳解
    一次性搞清楚equals和hashCode
    更多類(lèi)似文章 >>
    生活服務(wù)
    分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
    綁定賬號(hào)成功
    后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
    如果VIP功能使用有故障,
    可點(diǎn)擊這里聯(lián)系客服!

    聯(lián)系客服