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 {@Override
br/>@Override
return super.clone();}
@Override
br/>}
@Override
return super.hashCode();
}
}
Object類? 約12個方法,下面一一解釋這些方法的作用1. getClass()
public final Class<?> getClass() {
return shadow$klass;
}
返回此Object的運(yùn)行時類
實(shí)際結(jié)果的類型是Class<? extends |X|>其中|X|是靜態(tài)類型上其表達(dá)的擦除getClass被調(diào)用。 例如,在此代碼片段中不需要轉(zhuǎn)換:
Number n = 0;?
Class<? extends Number> c = n.getClass();
成都創(chuàng)新互聯(lián)主營梁山網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,成都app軟件開發(fā),梁山h5成都小程序開發(fā)搭建,梁山網(wǎng)站營銷推廣歡迎梁山等地區(qū)企業(yè)咨詢
- 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 的特點(diǎn)是:
1.只要在執(zhí)行Java應(yīng)用程序時多次在同一個對象上調(diào)用該方法,hashcode()始終返回相同的整數(shù)(前提是該對象的信息沒有發(fā)生改變)
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");
}
return internalClone();
}
克隆方法:創(chuàng)建并返回此對象的副本;
對于任何對象x x.clone()!=x
而且x.clone().getClass()==x.getClass() 成立 雖然對象的基類都支持clone 但是object本身并未實(shí)現(xiàn)cloneable,所以自定義的類需要實(shí)現(xiàn)cloneable接口,否則將拋出異常
toString()
返回對象的字符串表示形式,一般說來,這個方法返回一個固定的模版public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
這個在實(shí)際開發(fā)中,并不好體現(xiàn),所以各大編譯器都支持 重新生成toString(),如:
public static class User {
private String name;
private int age;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 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()方法可以被子類對象所覆蓋,然后作為一個終結(jié)者,當(dāng)GC被調(diào)用的時候完成最后的清理工作(例如釋放系統(tǒng)資源之類)。這就是終止。默認(rèn)的finalize()方法什么也不做,當(dāng)被調(diào)用時直接返回。
對于任何一個對象,它的finalize()方法都不會被JVM執(zhí)行兩次。如果你想讓一個對象能夠被再次調(diào)用的話(例如,分配它的引用給一個靜態(tài)變量),注意當(dāng)這個對象已經(jīng)被GC回收的時候,finalize()方法不會被調(diào)用第二次。測試:
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
br/>@Override
return "User{" +
"name='" + name + '\'' +
", age=" + age +'}';
}
@Override
br/>'}';
}
@Override
System.out.println("finalize");
super.finalize();
}
}
public static void main(String[] args) throws Exception {
User o = new User();
o = null;
System.gc();
System.gc();
}
}
運(yùn)行結(jié)果:
asange.javastudy.java.lang.ObjectTest
finalize
Process finished with exit code 0
可以看到結(jié)果:兩次gc finalize 只執(zhí)行了一次
- wait()? notify() notifyAll()
這三個方法是有關(guān)線程阻塞與線程喚醒 - wait(),notify()與notifyAll()方法是本地方法,并且是final類型,無法重寫
- 調(diào)用某個對象的wait()方法能讓當(dāng)前線程阻塞,并且當(dāng)前線程必須擁有此對象的monitor(即鎖)
- 調(diào)用某個對象的notify()方法能喚醒一個正在等待這個對象的monitor的線程,如果有多個線程在等待這個monitor,喚醒其中一個線程;
- 調(diào)用notifyAll()方法能喚醒所有正在等待這個對象的monitor為何這三個不是Thread類聲明中的方法,而是Object類中聲明的方法(當(dāng)然由于Thread類繼承了Object類,所以Thread也可以調(diào)用者三個方法)?其實(shí)這個問題很簡單,由于每個對象都擁有monitor(即鎖),所以讓當(dāng)前線程等待某個對象的鎖,當(dāng)然應(yīng)該通過這個對象來操作了。而不是用當(dāng)前線程來操作,因?yàn)楫?dāng)前線程可能會等待多個線程的鎖,如果通過線程來操作,就非常復(fù)雜了。
上面已經(jīng)提到,如果調(diào)用某個對象的wait()方法,當(dāng)前線程必須擁有這個對象的monitor(即鎖),因此調(diào)用wait()方法必須在同步塊或者同步方法中進(jìn)行(synchronized塊或者synchronized方法)。
調(diào)用某個對象的wait()方法,相當(dāng)于讓當(dāng)前線程交出此對象的monitor,然后進(jìn)入等待狀態(tài),等待后續(xù)再次獲得此對象的鎖(Thread類中的sleep方法使當(dāng)前線程暫停執(zhí)行一段時間,從而讓其他線程有機(jī)會繼續(xù)執(zhí)行,但它并不釋放對象鎖);
notify()方法能夠喚醒一個正在等待該對象的monitor的線程,當(dāng)有多個線程都在等待該對象的monitor的話,則只能喚醒其中一個線程,具體喚醒哪個線程則不得而知。
同樣地,調(diào)用某個對象的notify()方法,當(dāng)前線程也必須擁有這個對象的monitor,因此調(diào)用notify()方法必須在同步塊或者同步方法中進(jìn)行(synchronized塊或者synchronized方法)?! ofityAll()方法能夠喚醒所有正在等待該對象的monitor的線程,這一點(diǎn)與notify()方法是不同的。
這里要注意一點(diǎn):notify()和notifyAll()方法只是喚醒等待該對象的monitor的線程,并不決定哪個線程能夠獲取到monitor。
舉個簡單的例子:假如有三個線程Thread1、Thread2和Thread3都在等待對象objectA的monitor,此時Thread4擁有對象objectA的monitor,當(dāng)在Thread4中調(diào)用objectA.notify()方法之后,Thread1、Thread2和Thread3只有一個能被喚醒。注意,被喚醒不等于立刻就獲取了objectA的monitor。假若在Thread4中調(diào)用objectA.notifyAll()方法,則Thread1、Thread2和Thread3三個線程都會被喚醒,至于哪個線程接下來能夠獲取到objectA的monitor就具體依賴于操作系統(tǒng)的調(diào)度了。
上面尤其要注意一點(diǎn),一個線程被喚醒不代表立即獲取了對象的monitor,只有等調(diào)用完notify()或者notifyAll()并退出synchronized塊,釋放對象鎖后,其余線程才可獲得鎖執(zhí)行。
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
br/>@Override
super.run();
System.out.println("線程" + Thread.currentThread().getName() + "開始");
synchronized (obj) {
try {
System.out.println("線程" + Thread.currentThread().getName() + "調(diào)用了object.wait()");
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("線程" + Thread.currentThread().getName() + "獲取到了鎖");
}
}
}
static class Thread2 extends Thread {@Override
br/>@Override
super.run();
System.out.println("線程" + Thread.currentThread().getName() + "開始");
synchronized (obj) {
obj.notify();
System.out.println("線程" + Thread.currentThread().getName() + "調(diào)用了object.notify()");
}
System.out.println("線程" + Thread.currentThread().getName() + "釋放了鎖");
}
}
}運(yùn)行結(jié)果:線程Thread-0開始
線程Thread-1開始
線程Thread-0調(diào)用了object.wait()
線程Thread-1調(diào)用了object.notify()
線程Thread-1釋放了鎖
線程Thread-0獲取到了鎖
Process finished with exit code 0
1、Object類的七大native方法:registerNatives()、getClass()、hashCode()、clone()、notify()、notifyAll()、wait(long)native關(guān)鍵字修飾的方法稱為本地方法,這些方法并不是用java實(shí)現(xiàn)的,考慮到實(shí)現(xiàn)的性能問題,大多是由C/C++編寫的程序,編譯成dll文件,再由java去加載這些dll文件,就可以通過java來調(diào)用dll中的函數(shù)了1)registerNatives()方法:主要是將用C/C++語言寫的一些方法,如hashCode、wait、notify等方法加載到j(luò)vm中,感興趣的可以去OpenJDK中查看相關(guān)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關(guān)鍵字不太了解的,可以看一下我的另一篇文章:Java源碼解析之 final關(guān)鍵字的使用詳解//class 是一個類的屬性,能獲取該類編譯時的類對象
System.out.println(Bird.class);//class com.somta.test.commonuseobj.objectobj.Bird//getClass() 是一個類的方法,它是獲取該類運(yùn)行時的類對象
System.out.println(bird.getClass());//class com.somta.test.commonuseobj.objectobj.Bird
3)hashCode()方法:返回一個整數(shù)的HashCode值,該值依賴于內(nèi)部表示堆的對象的指針,一般情況下,該方法都會被重寫。關(guān)于hashCode與equals的關(guān)系,我們只需要記住下面四句話(前提:需要重寫equals和hashCode方法,String、Integer、Boolean、Double等都重寫了這兩個方法,不重寫HashCode方法,任何對象的hashCodeZFX返傭www.fx61.com/brokerlist/zfx.html都是不相等的,并且equals方法也會使用Object中的equals方法,此時equals和==是等價的,equals比較的是棧中的引用,而非對象的值)1、如果兩個對象相等,則它們的hashCode值一定相等
2、如果兩個對象不相等,則它們的hashCode值不一定都不相等
3、如果兩個對象的hashCode值相等,兩個對象不一定相等
4、如果兩個對象的hashCode值不相等,兩個對象一定不相等4)clone()方法: 將一個對象克隆出一個新對象,要實(shí)現(xiàn)clone的對象一般需要先實(shí)現(xiàn)Cloneable接口才能達(dá)到克隆的目的,克隆其實(shí)也分“淺克隆”,“深克隆” ,Object類的克隆屬于“淺克隆”,關(guān)于克隆的知識,后續(xù)在寫文章說明,此處就不展開了5)notify()、notifyAll()、wait(long)方法: 這些方法后續(xù)在多線程中在具體講解2、Object類的常用方法:equals()、toString()
1)、equals()方法我們可能在以前的面試中被問到過關(guān)于 == 和 equals的區(qū)別,可能大多人的回答是:“==運(yùn)算符通常是用來比較基本類型的值是否相等或者比較對象的引用是否相等;equals比較的是兩個對象是否相等”,這種說法其實(shí)并不太正確,不妨我們先看Object中關(guān)于equals()方法的源碼public boolean equals(Object obj) {
return (this == obj);
}
Object類是所有類的子類,如果一個類沒有重寫equals()方法,那它就會使用父類的的equals()方法,通過上面的代碼可以看出其實(shí)在Object類中,==運(yùn)算符和equals()方法是等價的,其實(shí)上面的說法只適用于那些重寫了Object類equals方法的類而言是正確的,比如String等。注意:重寫equals()方法的時候,必須要重寫hashCode方法,以維護(hù)hashCode的約束,確保equals()方法聲明相等的對象具有相同的hashCode值2)、toString()方法public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
getClass().getName()返回了該類的全類名,Integer.toHexString(hashCode())返回了以16進(jìn)制無符號整數(shù)的形式返回了此hashCode的字符串,這個是根類Object的實(shí)現(xiàn),子類中一般都會重寫該方法
分享標(biāo)題:Java基礎(chǔ)知識之Object類
網(wǎng)站地址:http://www.rwnh.cn/article44/gposee.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、虛擬主機(jī)、營銷型網(wǎng)站建設(shè)、域名注冊、網(wǎng)站設(shè)計(jì)、網(wǎng)站策劃
廣告
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源:
創(chuàng)新互聯(lián)