// IntelliJ API Decompiler stub source generated from a class file // Implementation of methods is not availablepackage java.lang;public class Object { public Object() { /* compiled code */ } private static native void registerNatives(); public final native java.lang.Class<?> getClass(); public native int hashCode(); public boolean equals(java.lang.Object o) { /* compiled code */ } protected native java.lang.Object clone() throws java.lang.CloneNotSupportedException; public java.lang.String toString() { /* compiled code */ } public final native void notify(); public final native void notifyAll(); public final native void wait(long l) throws java.lang.InterruptedException; public final void wait(long l, int i) throws java.lang.InterruptedException { /* compiled code */ } public final void wait() throws java.lang.InterruptedException { /* compiled code */ } protected void finalize() throws java.lang.Throwable { /* compiled code */ }} Object是java所有類的終極類,我們常見的自訂class 但是並沒有繼承Object(Java編譯器自動引入,如果手動繼承Object,也是沒有問題的,java單繼承 有一定的局限)
public static class User { @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public int hashCode() { return super.hashCode(); } }
Object類 約12個方法,下面一一解釋這些方法的作用
1. getClass()
public final Class<?> getClass() { return shadow$_klass_; } 返回此Object的運行時類
實際結果的類型是Class<? extends |X|>其中|X|是靜態類型上其表達的擦除getClass被調用。 例如,在此程式碼片段中不需要轉換:
Number n = 0;
Class<? extends Number> c = n.getClass();
2. hashCode()
/* @return a hash code value for this object. * @see java.lang.Object#equals(java.lang.Object) * @see java.lang.System#identityHashCode */ public int hashCode() { return identityHashCode(this); } 返回對象的hash值,支援這種方法是為了散列表,如hashmap
hashcode 的特點是:
1.只要在執行Java應用程式時多次在同一個對象上調用該方法,hashcode()始終返回相同的整數(前提是該對象的資訊沒有發生改變)
2.相對於兩個對象來說,如果使用了equals方法比較返回true,那麼這兩個對象的hashcode值也是相同的
3. 對於兩個對象來說,如果使用equals方法比較為false,那麼這兩個對象的hash值不一定要求不同,可以相同也可以不同,然而如果不同,則可以提高效能
4. 對於Object類來說,不同的Object對象的hashcode是不同的(Object的hashcode 表示對象的儲存地址,但是如果重寫了hash code 就不一定表示儲存地址了)
3. Clone()
protected Object clone() throws CloneNotSupportedException { if (!(this instanceof Cloneable)) { throw new CloneNotSupportedException("Class " + getClass().getName() + " doesn't implement Cloneable"); } return internalClone(); } 複製方法:建立並返回此對象的副本 ; 對於任何對象x x.clone()!=x
而且x.clone().getClass()==x.getClass() 成立 雖然對象的基類都支援clone 但是object本身並未實現cloneable,所以自訂的類需要實現cloneable介面,否則將拋出異常
4. toString()
返回對象的字串表示形式,一般說來,這個方法返回一個固定的模版
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } 這個在實際開發中,並不好體現,所以各大編譯器都支援 重建toString(),如:
public static class User { private String name; private int age; @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
5. finalize()
/* @throws Throwable the {@code Exception} raised by this method * @see java.lang.ref.WeakReference * @see java.lang.ref.PhantomReference * @jls 12.6 Finalization of Class Instances */ protected void finalize() throws Throwable { } finalize()方法可以被子類對象所覆蓋,然後作為一個終結者,當GC被調用的時候完成最後的清理工作(例如釋放系統資源之類)。這就是終止。預設的finalize()方法什麼也不做,當被調用時直接返回。
對於任何一個對象,它的finalize()方法都不會被JVM執行兩次。如果你想讓一個對象能夠被再次調用的話(例如,分配它的引用給一個靜態變數),注意當這個對象已經被GC回收的時候,finalize()方法不會被調用第二次。
測試:
package asange.javastudy.java.lang;/** * @author youxuan E-mail:xuanyouwu@163.com * @version 2.3.1 * @Description * @date createTime:2018/1/20 */public class ObjectTest { public static class User { private String name; private int age; @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override protected void finalize() throws Throwable { System.out.println("finalize"); super.finalize(); } } public static void main(String[] args) throws Exception { User o = new User(); o = null; System.gc(); System.gc(); }}
運行結果:
asange.javastudy.java.lang.ObjectTestfinalizeProcess finished with exit code 0
可以看到結果:兩次gc finalize 只執行了一次
6. wait() notify() notifyAll() 這三個方法是有關線程阻塞與線程喚醒
1. wait(),notify()與notifyAll()方法是本地方法,並且是final類型,無法重寫
2. 調用某個對象的wait()方法能讓當前線程阻塞,並且當前線程必須擁有此對象的monitor(即鎖)
3. 調用某個對象的notify()方法能喚醒一個正在等待這個對象的monitor的線程,如果有多個線程在等待這個monitor,喚醒其中一個線程;
4. 調用notifyAll()方法能喚醒所有正在等待這個對象的monitor
為何這三個不是Thread類聲明中的方法,而是Object類中聲明的方法(當然由於Thread類繼承了Object類,所以Thread也可以調用者三個方法)。其實這個問題很簡單,由於每個對象都擁有monitor(即鎖),所以讓當前線程等待某個對象的鎖,當然應該通過這個對象來操作了。而不是用當前線程來操作,因為當前線程可能會等待多個線程的鎖,如果通過線程來操作,就非常複雜了。
上面已經提到,如果調用某個對象的wait()方法,當前線程必須擁有這個對象的monitor(即鎖),因此調用wait()方法必須在同步塊或者同步方法中進行(synchronized塊或者synchronized方法)。
調用某個對象的wait()方法,相當於讓當前線程交出此對象的monitor,然後進入等待狀態,等待後續再次獲得此對象的鎖(Thread類中的sleep方法使當前線程暫停執行一段時間,從而讓其他線程有機會繼續執行,但它並不釋放對象鎖);
notify()方法能夠喚醒一個正在等待該對象的monitor的線程,當有多個線程都在等待該對象的monitor的話,則只能喚醒其中一個線程,具體喚醒哪個線程則不得而知。
同樣地,調用某個對象的notify()方法,當前線程也必須擁有這個對象的monitor,因此調用notify()方法必須在同步塊或者同步方法中進行(synchronized塊或者synchronized方法)。
nofityAll()方法能夠喚醒所有正在等待該對象的monitor的線程,這一點與notify()方法是不同的。
這裡要注意一點:notify()和notifyAll()方法只是喚醒等待該對象的monitor的線程,並不決定哪個線程能夠擷取到monitor。
舉個簡單的例子:假如有三個線程Thread1、Thread2和Thread3都在等待對象objectA的monitor,此時Thread4擁有對象objectA的monitor,當在Thread4中調用objectA.notify()方法之後,Thread1、Thread2和Thread3隻有一個能被喚醒。注意,被喚醒不等於立刻就擷取了objectA的monitor。假若在Thread4中調用objectA.notifyAll()方法,則Thread1、Thread2和Thread3三個線程都會被喚醒,至於哪個線程接下來能夠擷取到objectA的monitor就具體依賴於作業系統的調度了。
上面尤其要注意一點,一個線程被喚醒不代表立即擷取了對象的monitor,只有等調用完notify()或者notifyAll()並退出synchronized塊,釋放對象鎖後,其餘線程才可獲得鎖執行。
public class ObjectTest { public static Object obj = new Object(); public static void main(String[] args) throws Exception { Object o2 = new Object(); Thread1 thread1 = new Thread1(); Thread2 thread2 = new Thread2(); thread1.start(); thread2.start(); } static class Thread1 extends Thread { @Override public void run() { super.run(); System.out.println("線程" + Thread.currentThread().getName() + "開始"); synchronized (obj) { try { System.out.println("線程" + Thread.currentThread().getName() + "調用了object.wait()"); obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程" + Thread.currentThread().getName() + "擷取到了鎖"); } } } static class Thread2 extends Thread { @Override public void run() { super.run(); System.out.println("線程" + Thread.currentThread().getName() + "開始"); synchronized (obj) { obj.notify(); System.out.println("線程" + Thread.currentThread().getName() + "調用了object.notify()"); } System.out.println("線程" + Thread.currentThread().getName() + "釋放了鎖"); } }}
運行結果:
線程Thread-0開始線程Thread-1開始線程Thread-0調用了object.wait()線程Thread-1調用了object.notify()線程Thread-1釋放了鎖線程Thread-0擷取到了鎖Process finished with exit code 0