Objects 對於Object 的關係類似於Collections 對於Collect,十分有意思
----------------------------------------------------------------------------------------------
更新:辛苦碼了這麼多字,結果發現一篇更好的博客,出於良心,文章就成轉載的了
1.Objects 的equals方法
比較兩個對象是否相等,依賴於對象重寫的equals方法(或object 的equals 方法比較地址)
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
2.deepEqualsf方法底層調用Arrays類的比較方法,因此一般可以比較 基本數組,如果是對象的話則依賴於對象自身的equals方法
//Objects 類
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 類
static boolean deepEquals0(Object e1, Object e2) {
assert e1 != null;
boolean eq;
if (e1 instanceof Object[] && e2 instanceof Object[])
eq = deepEquals ((Object[]) e1, (Object[]) e2);
else if (e1 instanceof byte[] && e2 instanceof byte[])
eq = equals((byte[]) e1, (byte[]) e2);
else if (e1 instanceof short[] && e2 instanceof short[])
eq = equals((short[]) e1, (short[]) e2);
else if (e1 instanceof int[] && e2 instanceof int[])
eq = equals((int[]) e1, (int[]) e2);
else if (e1 instanceof long[] && e2 instanceof long[])
eq = equals((long[]) e1, (long[]) e2);
else if (e1 instanceof char[] && e2 instanceof char[])
eq = equals((char[]) e1, (char[]) e2);
else if (e1 instanceof float[] && e2 instanceof float[])
eq = equals((float[]) e1, (float[]) e2);
else if (e1 instanceof double[] && e2 instanceof double[])
eq = equals((double[]) e1, (double[]) e2);
else if (e1 instanceof boolean[] && e2 instanceof boolean[])
eq = equals((boolean[]) e1, (boolean[]) e2);
else
eq = e1.equals(e2);
return eq;
}
3.toString 方法 調用String類的valueof 方法,當對象爲null時,輸出“null”,一定程度上防止直接toString的空指針
public static String toString(Object o) {
return String.valueOf(o);
}
//當o爲null時,使用非空默認值
public static String toString(Object o, String nullDefault) {
return (o != null) ? o.toString() : nullDefault;
}
4.非空判斷,要求一個對象非空,如果爲空則拋出異常。spring 項目可以使用Asserts.notNull(Obj,message)來斷言,java也有,
甚至你好可以在pom文件中引入
<dependency> <groupId>com.google.code.findbugs</groupId> <artifactId>jsr305</artifactId> <version>3.0.2</version> </dependency> <dependency> <groupId>org.jetbrains</groupId> <artifactId>annotations</artifactId> <version>15.0</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>20.0</version> </dependency>
直接在虛參聲明中寫@NotNull @NonNul 之類的,讓調用者去做空指針判斷
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
public static <T> T requireNonNull(T obj, String message) {
if (obj == null)
throw new NullPointerException(message);
return obj;
}
public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
if (obj == null)
throw new NullPointerException(messageSupplier.get());
return obj;
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
發現了一片更好的博客,轉載過來
https://www.cnblogs.com/quiet-snowy-day/p/6387321.html#label_0
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)。