【Java】java.util.Objects 源碼學習


2017-02-10 by 安靜的下雪天  http://www.cnblogs.com/quiet-snowy-day/p/6387321.html     

本篇概要

    equals    deepEquals   hashCode   hash

    toString   compare   requireNonNull   isNull   nonNull

 

Objects 與 Object 區別

Object 是 Java 中所有類的基類,位於java.lang包。
Objects 是 Object 的工具類,位於java.util包。它從jdk1.7開始才出現,被final修飾不能被繼承,擁有私有的構造函數。
它由一些靜態的實用方法組成,這些方法是null-save(空指針安全的)或null-tolerant(容忍空指針的),用於計算對象的hashcode、返回對象的字符串表示形式、比較兩個對象。

 

Objects 各方法介紹與分析

equals

equals方法是判斷兩個對象是否相等。
在比較兩個對象的時候,Object.equals方法容易拋出空指針異常。
——我剛上班的時候,有位老員工教我“字符串常量與變量對象比較的時候,常量要寫在equals外邊,變量放在equals()括號里邊。” 就是這個原因。
如果是兩個變量比較的時候,就都需要加非空判斷。
* Object.equals方法內調用的是return (this == obj)。String類中是依據字符串內容是否相等來重定義了equals方法。

現在,Objects.equals方法中已經做了非空判斷,所以不會拋出空指針異常,它是null-save空指針安全的,而且也可以簡化代碼。

源碼如下:

    public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }

返回目錄

 

 

deepEquals

顧名思義,深度比較兩個對象。
當參數是數組對象,其方法內部采用的是Arrays.deepEquals0方法的算法。
使用Objects.deepEquals方法有個好處,當我們在寫業務代碼時,可以直接使用此方法來判斷兩個復雜類型,
比如使用了泛型的列表對象List<T>、或者通過反射得到的對象,不清楚對象的具體類型。
源碼如下:
    public static boolean deepEquals(Object a, Object b) {
        if (a == b)
            return true;
        else if (a == null || b == null)
            return false;
        else
            return Arrays.deepEquals0(a, b);
    }

 簡短的說明下Arrays.deepEquals0方法:

     如果參數是Object類型的數組,則調用Arrays.deepEquals方法,在參數數組的循環中,遞歸調用deepEquals0,直到出現不相同的元素, 或者循環結束;
     如果參數是基本類型的數組,則根據該類型調用Arrays.equals方法。Arrays工具類依照八種基本類型對equals方法做了重載。
 

返回目錄

 

 

hashCode

返回一個整型數值,表示該對象的哈希碼值。若參數對象為空,則返回整數0;若不為空,則直接調用了Object.hashCode方法。
源碼如下:
    public static int hashCode(Object o) {
        return o != null ? o.hashCode() : 0;
    }

Object支持hashCode方法是為了提高哈希表(例如java.util.Hashtable 提供的哈希表)的性能。

以集合Set為例,當新加一個對象時,需要判斷現有集合中是否已經存在與此對象相等的對象,如果沒有hashCode()方法,需要將Set進行一次遍歷,並逐一用equals()方法判斷兩個對象是否相等,此種算法時間復雜度為o(n)。通過借助於hasCode方法,先計算出即將新加入對象的哈希碼,然后根據哈希算法計算出此對象的位置,直接判斷此位置上是否已有對象即可。
(注:Set的底層用的是Map的原理實現)
 

返回目錄

 

 

hash

為一系列的輸入值生成哈希碼,該方法的參數是可變參數。
源碼如下:
    public static int hash(Object... values) {
        return Arrays.hashCode(values);
    }

它是將所有的輸入值都放到一個數組,然后調用Arrays.hashCode(Object[])方法來實現哈希碼的生成。

對於當一個對象包含多個成員,重寫Object.hashCode方法時,hash方法非常有用。
舉個Java源碼中的例子:
java.lang.invoke.MemberName 類,該類有Class<?> clazz、String name、Object type、int flags、Object resoulution這幾個成員變量,
該類的hashCode方法如下:
    @Override
    public int hashCode() {
        return Objects.hash(clazz, getReferenceKind(), name, getType());
    }

 警告:當提供的參數是一個對象的引用,返回值不等於該對象引用的散列碼。這個值可以通過調用hashCode方法來計算。

 

返回目錄

 

 

toString

  toString(Object o)

  返回指定對象的字符串表示形式。如果參數為空對象null,則返回字符串“null”。
  該方法內部調用的是
     return String.valueOf( o );
  String.valueOf(Object obj)方法的內部實現為
     return ( obj == null ) ? "null" : obj .toString();
  Object.toString()方法的內部實現為
     return getClass().getName() + "@" + Integer.toHexString(hashCode());

  toString(Object o, String nullDefault)

  返回指定對象的字符串表示形式。如果參數為空對象null,則返回第二個參數nullDefault所指定的對象。

返回目錄

 

 

compare

如果兩個參數相同則返回整數0。因此,如果兩個參數都為空對象null,也是返回整數0。
注意:如果其中一個參數是空對象null,是否會拋出空指針異常NullPointerException取決於排序策略,如果有的話,則由Comparator來決定空值null。
源碼如下:
    public static <T> int compare(T a, T b, Comparator<? super T> c) {
        return (a == b) ? 0 :  c.compare(a, b);
    }

返回目錄

 

 

requireNonNull

  requireNonNull(T obj)

  檢查指定類型的對象引用不為空null。當參數為null時,拋出空指針異常。設計這個方法主要是為了在方法、構造函數中做參數校驗。

  源碼如下:

    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

  舉個例子:

  當我們通過帶參的構造函數創建對象時,創建對象的同時就可以進行參數校驗。同時也簡化了很多代碼。
     public class Foo {
          public Foo(Bar bar) {
               this.bar = Objects.requireNonNull(bar);
          }
     }

 

  requireNonNull(T obj, String message) 

  該方法是requireNonNull的重載方法,當被校驗的參數為null時,根據第二個參數message拋出自定義的異常消息。
  源碼如下:
    public static <T> T requireNonNull(T obj, String message) {
        if (obj == null)
            throw new NullPointerException(message);
        return obj;
    }

 

  requireNonNull(T obj, Supplier<String> messageSupplier)

  檢查指定的對象引用不為空null,如果是空,拋出自定義的空指針異常。從jdk1.8開始。
  與requireNonNull(Object, String)方法不同,本方法允許將消息的創建延遲,直到空檢查結束之后。
  雖然在非空例子中這可能會帶來性能優勢, 但是決定調用本方法時應該小心,創建message supplier的開銷低於直接創建字符串消息。  
  源碼如下:
    public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
        if (obj == null)
            throw new NullPointerException(messageSupplier.get());
        return obj;
    }

返回目錄

 

 

isNull

判空方法,如果參數為空則返回true。從jdk1.8開始。

源碼如下:

    public static boolean isNull(Object obj) {
        return obj == null;
    }
apiNote: 該方法的存在是用於java.util.function.Predicate類,filter(Objects::isNull)。
來看下Predicate類中,使用到本方法的代碼: 
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)  
                ? Objects::isNull   // 雙冒號,代表方法引用。
                : object -> targetRef.equals(object); // 此處為lambda表達式。接收object對象,返回參數targetRef與該對象的比較結果。
    }
 

 

nonNull

判斷非空方法,如果參數不為空則返回true。從jdk1.8開始。

源碼如下:

    public static boolean nonNull(Object obj) {
        return obj != null;
    }

apiNote: 該方法的存在是用於java.util.function.Predicate類,filter(Objects::nonNull)。

返回目錄

 

 

參考資料:

如果覺得有幫助,請鼓勵下博主吧:)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM