JDK源碼之-java.lang.Object

JDK源碼之-java.lang.Object

JDK源碼之-java.lang.Object

public final native Class> getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
protected void finalize()throwsThrowable { }

equals 方法

// equals 方法
// 在面試中面試官經常會問 equals() 方法和 == 運算符的區別,== 運算符用於比較基本類型的值是否相同而 equals 用於比較兩個對象是否相等,那麼有個問題來了,兩個對象怎麼才算是相等的呢。 看object中的equals實現
public boolean equals(Object obj)
{
return (this == obj);
}
// 在Object中equals和==是等價的。所以在Object中兩個對象的引用相同,那麼一定就是相同的。在我們自定義對象的時候一定要重寫equals方法。我參考了以下網上的資料來分析一下String中重寫的 equals方法:

public boolean equals(Object anObject)
{
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length)
{
char v1[] = value; char v2[] = anotherString.value;
int i = 0;
while (n-- != 0)
{
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
// String 是引用類型,比較時不能比較引用是否相等,重點是字符串的內容是否相等。所以 String 類定義兩個對象相等的標準是字符串內容都相同。
// 在Java規範中,對 equals 方法的使用必須遵循以下幾個原則:
// 自反性:對於任何非空引用值 x,x.equals(x) 都應返回 true。
對稱性:對於任何非空引用值 x 和 y,當且僅當 y.equals(x) 返回 true 時,x.equals(y) 才應返回 true。
// 傳遞性:對於任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,並且 y.equals(z) 返回 true,那麼 x.equals(z) 應返回 true。
// 一致性:對於任何非空引用值 x 和 y,多次調用 x.equals(y) 始終返回 true 或始終返回 false,前提是對象上 equals 比較中所用的信息沒有被修改
// 對於任何非空引用值 x,x.equals(null) 都應返回 false

// 我們在判斷的時候使用了instanceof關鍵字來判斷運行的時候是否是指定的類型
// java 中的instanceof 運算符是用來在運行時指出對象是否是特定類的一個實例。instanceof通過返回一個布爾值來指出,這個對象是否是這個特定類或者是它的子類的一個實例。
// 注意:使用getClass是要根據情況而定,使用getClass 不符合多態的定義
// 那什麼時候使用instanceof,什麼時候使用getClass呢?
// 如果子類能夠擁有自己的相等概念,則對稱性需求將強制採用 getClass 進行檢測。
// 如果有超類決定相等的概念,那麼就可以使用 instanceof 進行檢測,這樣可以在不同的子類的對象之間進行相等的比較。
// 還有就是一定要注意無論何時重寫此方法,通常都必須重寫hashCode方法,以維護hashCode方法的一般約定,該方法聲明相等對象必須具有相同的哈希代碼。

getClass 方法

// getClass 方法
// 我們看到getClass被native標識,這代表這是調用本地方法實現
// native是由操作系統幫我們實現
// 文檔說明的是調用getClass返回一個運行時的類。
// 可以看出getClass是返回一個運行時的對象。class是返回編譯的類對象

// 可以看到getClass方法被final修飾,說明此方法不能被重寫。

hashCode 方法

hashCode也是一個被native修飾的本地方法
註釋說明的是返回該對象的哈希值。那麼它有什麼作用呢?
主要是保證基於散列的集合,如HashSet、HashMap以及HashTable等,在插入元素時保證元素不可重複,同時為了提高元素的插入刪除便利效率而設計;主要是為了查找的便捷性而存在。
就比如使用Set進行舉例子。
Set集合是不可重複的,如果每次添加數據都使用equals去做對比的話,插入十萬條數據就要對比十萬次效率是非常慢的。
所以在添加數據的時候使用了哈希表,哈希算法也稱之為散列算法,當添加一個值的時候先算出它的哈希值根據算出的哈希值將數據插入指定位置。這樣的話就避免了一直調用equals造成的效率隱患。同時有以下條件:
如果位置為空則直接添加
如果位置不為空,判斷兩個元素是否相同如果相同則不存儲。
還有一種情況是兩個元素不相同,但是hashCode相同,這就是哈希碰撞。
如果發生了hash key相同的情況就在相同的元素創建一個鏈表。把所有相同的元素存放在鏈表中。

可以看出T1的哈希和T2相同,但是元素不同,所以現在會形成一個鏈來存儲。

toString 方法

可以看出toString是返回的類名加16進制無符號整數形式返回此哈希碼的字符串表示形式。
運行輸出結果:
直接輸出對象和使用toString是一樣的
如果想要toString輸出屬性內容則需要重寫toString方法

finalize 方法

// finalize用戶垃圾回收是由JVM調用。

registerNatives

// 上面說到native是調用本地實現方法,而registerNatives則是對本地方法註冊,裝載本地庫。在Object初始化時執行。
JDK源碼之-java.lang.Object


分享到:


相關文章: