這是《水煮 JDK 源碼》系列 的第 10 篇文章,計劃撰寫100篇關于JDK源碼相關的文章
Objects
類位于
java.util
包下,自 JDK 1.7 版本新增的,它是一個 final 類,不能被繼承,且構造函數是 private 的,不能被執行個體化,它提供了一系列操作Object對象的靜态方法,通常會被當做工具類去使用,其類定義如下:
public final class Objects {}
Objects
類在
jdk
源碼中應用很廣泛,通過
Intellij Idea
搜尋一下在
rt.jar
包中的應用,部分截圖如下:
::: hljs-center

:::
從上面的搜尋結果可以看出,在
jdk 1.8
版本中,大概有
366
處使用了
Objects
類的相關方法,下面結合具體的源碼來分析一下。
1、構造函數
Objects
類不能被執行個體化,其構造函數是私有的,實作如下:
private Objects() {
throw new AssertionError("No java.util.Objects instances for you!");
}
2、方法
Objects
類提供的靜态方法大緻可以分為以下的幾類:
- equals:比較兩個對象是否相同
- hash:擷取對象的哈希值;
- toString:将對象轉換為字元串
- requireNonNull:要求對象不為空
- isNull:判斷對象是否為空
- nonNull:判斷對象不為空
具體可以通過下面的結構圖來看看這些方法:
::: hljs-center
:::
2.1 equals 方法
equals()
方法主要用于比較兩個指定的對象是否相同,定義如下:
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
除了
equals()
方法外,還有一個
deepEquals()
方法,該方法用于比較兩個對象是否完全相同,可用于比較兩個數組對象是否相同,其定義如下:
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()
方法,其實作如下:
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
// 如果不是數組類型,則直接使用 Object.equals() 方法比較
eq = e1.equals(e2);
return eq;
}
上面的方法實作中,會逐個比較數組中的元素是否相同,如果都相同,則兩個數組相同。
2.2 hashCode 方法
hashCode()
方法用于擷取對象的哈希值,其實作如下:
public static int hashCode(Object o) {
// 如果對象不為空,則調用 Object 的 hashCode() 方法
// 否則直接傳回 0
return o != null ? o.hashCode() : 0;
}
除了可以擷取單個對象的哈希值外,
Objects
還提供了可以擷取多個對象的哈希值,即
hash()
方法,如下:
public static int hash(Object... values) {
return Arrays.hashCode(values);
}
該方法的參數為可變長參數,具體實作是調用
Arrays.hashCode
方法,其源碼如下:
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
從上面的實作可以看出,數組元素的哈希值是所有元素的哈希值經過一定變換後的和。
2.3 toString 方法
toString()
方法就是将對象轉換為字元串,如果對象為
null
,則會直接傳回
null
字元串,其實作如下:
public static String toString(Object o) {
return String.valueOf(o);
}
public static String toString(Object o, String nullDefault) {
// 如果對象為null,則可以傳回一個預設值
return (o != null) ? o.toString() : nullDefault;
}
toString()
方法具體實作調用的是
String.valueOf()
方法,而
String.valueOf()
方法又會調用
Object.toString()
方法,其源碼如下:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
2.4 requireNonNull 方法
requireNonNull()
方法用于判定參數對象是否為空,如果對象為空,則會抛出空指針異常,其實作如下:
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) {
// 通過一個 Supplier 來擷取空指針異常資訊
if (obj == null)
throw new NullPointerException(messageSupplier.get());
return obj;
}
requireNonNull()
有3個重載方法,可以指定抛出空指針異常時的資訊,對于第三個方法,可以傳入一個
Supplier
,在對象為空時,動态的建構空指針異常資訊,如果一個方法要求參數不能為空,那麼就可以直接使用該方法對參數進行空校驗。
2.5 isNull 方法
isNull()
方法判定對象為空,其實作比較簡單,如下:
public static boolean isNull(Object obj) {
return obj == null;
}
2.6 nonNull 方法
public static boolean nonNull(Object obj) {
return obj != null;
}