【Java】java.util.Objects 工具類方法研究
阿新 • • 發佈:2019-01-26
(this==
obj)。String類中是依據字串內容是否相等來重定義了equals方法。
它是將所有的輸入值都放到一個數組,然後呼叫Arrays.hashCode(Object[])方法來實現雜湊碼的生成。 對於當一個物件包含多個成員,重寫Object.hashCode方法時,hash方法非常有用。 舉個Java原始碼中的例子: java.lang.invoke.MemberName 類,該類有Class<?> clazz、String name、Object type、int flags、Object resoulution這幾個成員變數, 該類的hashCode方法如下:
apiNote: 該方法的存在是用於java.util.function.Predicate類,filter(Objects::isNull)。 來看下Predicate類中,使用到本方法的程式碼:
apiNote: 該方法的存在是用於java.util.function.Predicate類,filter(Objects::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現在,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”。 該方法內部呼叫的是 returnString.valueOf(o); String.valueOf(Object obj)方法的內部實現為 return(obj==null) ?"null":obj.toString(); Object.toString()方法的內部實現為 returngetClass().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)。