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

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

本篇概要

    equals    deepEquals   hashCode   hashjava

    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空指針安全的,並且也能夠簡化代碼。api

源碼以下:數組

    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方法:oracle

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

返回目錄ide

 

 

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)。

返回目錄

 

 

參考資料:

若是以爲有幫助,請鼓勵下博主吧:)

相關文章
相關標籤/搜索