package 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 {br/>@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();br/>}
@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();html
- 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值也是相同的
- 對於兩個對象來講,若是使用equals方法比較爲false,那麼這兩個對象的hash值不必定要求不一樣,能夠相同也能夠不一樣,然而若是不一樣,則能夠提升性能4. 對於Object類來講,不一樣的Object對象的hashcode是不一樣的(Object的hashcode 表示對象的存儲地址,可是若是重寫了hashcode 就不必定表示存儲地址了)
-
Clone()
protected Object clone() throws CloneNotSupportedException {
if (!(this instanceof Cloneable)) {
throw new CloneNotSupportedException("Class " + getClass().getName() +
" doesn't implement Cloneable");
}java
return internalClone();
}
克隆方法:建立並返回此對象的副本;
對於任何對象x x.clone()!=x
並且x.clone().getClass()==x.getClass() 成立 雖然對象的基類都支持clone 可是object自己並未實現cloneable,因此自定義的類須要實現cloneable接口,不然將拋出異常面試
-
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 +
'}';
}
}jvm
- 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;br/>@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +br/>'}';
}
@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.ObjectTest
finalize
Process finished with exit code 0
能夠看到結果:兩次gc finalize 只執行了一次
- wait() notify() notifyAll()
這三個方法是有關線程阻塞與線程喚醒
- wait(),notify()與notifyAll()方法是本地方法,而且是final類型,沒法重寫
- 調用某個對象的wait()方法能讓當前線程阻塞,而且當前線程必須擁有此對象的monitor(即鎖)
- 調用某個對象的notify()方法能喚醒一個正在等待這個對象的monitor的線程,若是有多個線程在等待這個monitor,喚醒其中一個線程;
- 調用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。
舉個簡單的例子:假若有三個線程Thread一、Thread2和Thread3都在等待對象objectA的monitor,此時Thread4擁有對象objectA的monitor,當在Thread4中調用objectA.notify()方法以後,Thread一、Thread2和Thread3只有一個能被喚醒。注意,被喚醒不等於馬上就獲取了objectA的monitor。倘若在Thread4中調用objectA.notifyAll()方法,則Thread一、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 {br/>@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 {br/>@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
一、Object類的七大native方法:registerNatives()、getClass()、hashCode()、clone()、notify()、notifyAll()、wait(long)native關鍵字修飾的方法稱爲本地方法,這些方法並非用java實現的,考慮到實現的性能問題,大可能是由C/C++編寫的程序,編譯成dll文件,再由java去加載這些dll文件,就能夠經過java來調用dll中的函數了1)registerNatives()方法:主要是將用C/C++語言寫的一些方法,如hashCode、wait、notify等方法加載到jvm中,感興趣的能夠去OpenJDK中查看相關C的代碼以下static JNINativeMethod methods[] = { {「hashCode」, 「()I」, (void )&JVM_IHashCode}, {「wait」, 「(J)V」, (void )&JVM_MonitorWait}, {「notify」, 「()V」, (void )&JVM_MonitorNotify}, {「notifyAll」, 「()V」, (void )&JVM_MonitorNotifyAll}, {「clone」, 「()Ljava/lang/Object;」, (void )&JVM_Clone},};JNIEXPORT void JNICALLJava_java_lang_Object_registerNatives(JNIEnv env, jclass cls)
{
(*env)->RegisterNatives(env, cls,methods, sizeof(methods)/sizeof(methods[0]));
}
2)getClass()方法:咱們能夠看到這個方法是由final修飾的,所以不能被重寫的,對final關鍵字不太瞭解的,能夠看一下個人另外一篇文章:Java源碼解析之 final關鍵字的使用詳解//class 是一個類的屬性,能獲取該類編譯時的類對象System.out.println(Bird.class);//class com.somta.test.commonuseobj.objectobj.Bird//getClass() 是一個類的方法,它是獲取該類運行時的類對象System.out.println(bird.getClass());//class com.somta.test.commonuseobj.objectobj.Bird3)hashCode()方法:返回一個整數的HashCode值,該值依賴於內部表示堆的對象的指針,通常狀況下,該方法都會被重寫。關於hashCode與equals的關係,咱們只須要記住下面四句話(前提:須要重寫equals和hashCode方法,String、Integer、Boolean、Double等都重寫了這兩個方法,不重寫HashCode方法,任何對象的hashCodeZFX返傭www.fx61.com/brokerlist/zfx.html都是不相等的,而且equals方法也會使用Object中的equals方法,此時equals和==是等價的,equals比較的是棧中的引用,而非對象的值)一、若是兩個對象相等,則它們的hashCode值必定相等二、若是兩個對象不相等,則它們的hashCode值不必定都不相等三、若是兩個對象的hashCode值相等,兩個對象不必定相等四、若是兩個對象的hashCode值不相等,兩個對象必定不相等4)clone()方法: 將一個對象克隆出一個新對象,要實現clone的對象通常須要先實現Cloneable接口才能達到克隆的目的,克隆其實也分「淺克隆」,「深克隆」 ,Object類的克隆屬於「淺克隆」,關於克隆的知識,後續在寫文章說明,此處就不展開了5)notify()、notifyAll()、wait(long)方法: 這些方法後續在多線程中在具體講解二、Object類的經常使用方法:equals()、toString()1)、equals()方法咱們可能在之前的面試中被問到過關於 == 和 equals的區別,可能大多人的回答是:「==運算符一般是用來比較基本類型的值是否相等或者比較對象的引用是否相等;equals比較的是兩個對象是否相等」,這種說法其實並不太正確,不妨咱們先看Object中關於equals()方法的源碼public boolean equals(Object obj) {return (this == obj);}Object類是全部類的子類,若是一個類沒有重寫equals()方法,那它就會使用父類的的equals()方法,經過上面的代碼能夠看出其實在Object類中,==運算符和equals()方法是等價的,其實上面的說法只適用於那些重寫了Object類equals方法的類而言是正確的,好比String等。注意:重寫equals()方法的時候,必需要重寫hashCode方法,以維護hashCode的約束,確保equals()方法聲明相等的對象具備相同的hashCode值2)、toString()方法public String toString() {return getClass().getName() + "@" + Integer.toHexString(hashCode());}getClass().getName()返回了該類的全類名,Integer.toHexString(hashCode())返回了以16進制無符號整數的形式返回了此hashCode的字符串,這個是根類Object的實現,子類中通常都會重寫該方法