摘要
大家都知道Object是所有類的父類,任何類都默認繼承Object,因此省略了extends Object關鍵字。Objec類中的方法在任何一個java類中都可以使用,下面學習的類的順序以jdk源碼爲準
Object類的常用方法:toString(),getClass(),hashCode(),equals(),clone(),finalize()
定義爲final類型,不能重寫的方法:getClass(),notify(),notifyAll(),wait()
1、registerNatives方法:
private static native void registerNatives();
static {
registerNatives();
}
registerNatives被native修飾爲本地方法,這些方法不是由java語言編寫,通常由C、C++語言編寫。被static修飾爲靜態方法。而且在靜態代碼塊中,Object類加載的時候會先執行registerNatives方法,registerNatives方法會進行一些跟系統有關的方法調用,而這個方法的實現就在java.dll中,裏面會根據不同系統來執行不同的底層操作。
2、getClass方法:
public final native Class<?> getClass();
getClass被native修飾爲本地方法,被final修飾子類不能夠重寫此方法,返回值採用泛型,返回Object的運行時類類型,一般和getName()聯合使用,如getClass().getName()。通過該方法或以獲取類的元數據和方法信息。它能夠獲取一個類的定義信息,然後使用反射去訪問類的全部信息,包括函數和字段。
3、hashCode方法:
public native int hashCode();
hashCode被native修飾爲本地方法,該方法返回該對象的哈希碼值,hashCode方法在一些具有哈希功能的Collection中用到。用於哈希查找,可以減少在查找中使用equals的次數,重寫了equals方法一般都要重寫hashCode方法。
根據官方文檔的定義,整理以下關鍵點:
- hashCode的存在主要是用於查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲結構中確定對象的存儲地址的;
- 如果兩個對象相同,就是滿足於equals(Java.lang.Object) 方法,那麼這兩個對象的hashCode一定要相同;
- 如果對象的equals方法被重寫,那麼對象的hashCode也儘量重寫,並且產生hashCode使用的對象,一定要和equals方法中使用的一致,否則就會違反上面第2點;
- 兩個對象的hashCode相同,並不一定表示兩個對象就相同,也就是不一定適用於equals(java.lang.Object) 方法,只能夠說明這兩個對象在散列存儲結構中,如Hashtable,他們“存放在同一個籃子裏”。
深入理解hashcode和hash算法請移步於:https://blog.csdn.net/qq_38182963/article/details/78940047
4、equals方法:
public boolean equals(Object obj) {
return (this == obj);
}
equals直接判斷this和obj本身的值是否相等,即用來判斷調用equals的對象和形參obj所引用的對象是否是同一對象。這裏的==比較的是對象的引用,也就是"地址值",如果this和obj指向的是同一塊內存對象,則返回true,如果this和obj指向的不是同一塊內存,則返回false。如果希望不同內存但相同內容的兩個對象equals時返回true,則我們需要重寫父類的equal方法,String類已經重寫了object中的equals方法,比較內容是否相等。
5、clone方法:
protected native Object clone() throws CloneNotSupportedException;
clone被native修飾爲本地方法,protected保護方法,實現對象的淺複製,只有實現了Cloneable接口纔可以調用該方法,否則拋出CloneNotSupportedException異常。
6、toString方法:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString方法返回一個字符串,類名+@+哈希值的16進制無符號整數形式。該方法用得比較多,一般子類都有覆蓋。
public class Test1 {
public static void main(String[] args){
Object o1 = new Object();
System.out.println(o1.toString());
}
}
//輸出:java.lang.Object@7852e922
7、notify方法:
public final native void notify();
notify被native修飾爲本地方法,不可被重寫,該方法喚醒在該對象上等待的某個線程。
8、notifyAll方法:
public final native void notifyAll();
notifyAll被native修飾爲本地方法,不可被重寫,該方法喚醒在該對象上等待的所有線程。
9、wait(long timeout)方法:
public final native void wait(long timeout) throws InterruptedException;
wait被native修飾爲本地方法,不可被重寫,調用該方法後當前線程進入睡眠狀態,讓當前線程等待,使線程等待指定長的時間(毫秒)。在其他線程調用了notify或是notifyAll方法或是達到指定的時長,該線程就可以被調度。其他線程調用了interrupt中斷該線程,就拋出一個InterruptedException異常。
10、wait(long timeout, int nanos)方法:
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 >= 500000 || (nanos != 0 && timeout == 0)) {
timeout++;
}
wait(timeout);
}
wait不可被重寫,和wait(long timeout)方法本質相同,允許更好地控制在放棄之前等待通知的時間,實時量,以毫微秒計算,計算公式如下:1000000*timeout+nanos,特別是wait(0, 0) 表示和wait(0)相同,當前線程必須擁有該對象的監視器。
三種異常:
- IllegalArgumentException – 如果超時的值是負的或毫微秒的值不在0-999999範圍內。
- IllegalMonitorStateException – 如果當前線程不是對象監視器的擁有者。
- InterruptedException – 如果另一個線程中斷了當前線程。當這種異常被拋出當前線程的中斷狀態被清除。
11、wait方法:
public final void wait() throws InterruptedException {
wait(0);
}
實際上調用的是wait(long timeout)方法只不過timeout傳的是0,只有調用了notify或是notifyAll方法,線程纔會被喚醒。
12、finalize方法:
protected void finalize() throws Throwable { }
該方法是protected方法,子類可以覆蓋該方法以實現資源清理工作,GC在回收對象之前調用該方法。該方法與C++中的析構函數不是對應的。C++中的析構函數調用的時機是確定的(對象離開作用域或delete掉),但Java中的finalize的調用具有不確定性。
finalize的執行週期:當對象變成(GC Roots)不可達時,GC會判斷該對象是否覆蓋了finalize方法,若未覆蓋,則直接將其回收。否則,若對象未執行過finalize方法,將其放入F-Queue隊列,由一低優先級線程執行該隊列中對象的finalize方法。執行finalize方法完畢後,GC會再次判斷該對象是否可達,若不可達,則進行回收,否則,對象“復活”。