溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Java基礎(chǔ)知識(shí)之Object類(lèi)

發(fā)布時(shí)間:2020-07-17 01:13:04 來(lái)源:網(wǎng)絡(luò) 閱讀:181 作者:專(zhuān)注地一哥 欄目:編程語(yǔ)言

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所有類(lèi)的終極類(lèi),我們常見(jiàn)的自定義class 但是并沒(méi)有繼承Object(Java編譯器自動(dòng)引入,如果手動(dòng)繼承Object,也是沒(méi)有問(wèn)題的,java單繼承 有一定的局限)
public static class User {@Override
br/>@Override
return super.clone();}
@Override
br/>}
@Override
return super.hashCode();
}
}
Object類(lèi)? 約12個(gè)方法,下面一一解釋這些方法的作用1. getClass()
public final Class<?> getClass() {
return shadow$klass;
}
返回此Object的運(yùn)行時(shí)類(lèi)
實(shí)際結(jié)果的類(lèi)型是Class<? extends |X|>其中|X|是靜態(tài)類(lèi)型上其表達(dá)的擦除getClass被調(diào)用。 例如,在此代碼片段中不需要轉(zhuǎn)換:
Number n = 0;?
Class<? extends Number> c = n.getClass();

  1. 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);
      }
      返回對(duì)象的hash值,支持這種方法是為了散列表,如hashmap
      hashcode 的特點(diǎn)是:
      1.只要在執(zhí)行Java應(yīng)用程序時(shí)多次在同一個(gè)對(duì)象上調(diào)用該方法,hashcode()始終返回相同的整數(shù)(前提是該對(duì)象的信息沒(méi)有發(fā)生改變)
      2.相對(duì)于兩個(gè)對(duì)象來(lái)說(shuō),如果使用了equals方法比較返回true,那么這兩個(gè)對(duì)象的hashcode值也是相同的
  2. 對(duì)于兩個(gè)對(duì)象來(lái)說(shuō),如果使用equals方法比較為false,那么這兩個(gè)對(duì)象的hash值不一定要求不同,可以相同也可以不同,然而如果不同,則可以提高性能4. 對(duì)于Object類(lèi)來(lái)說(shuō),不同的Object對(duì)象的hashcode是不同的(Object的hashcode 表示對(duì)象的存儲(chǔ)地址,但是如果重寫(xiě)了hashcode 就不一定表示存儲(chǔ)地址了)
  3. Clone()
    protected Object clone() throws CloneNotSupportedException {
    if (!(this instanceof Cloneable)) {
    throw new CloneNotSupportedException("Class " + getClass().getName() +
    " doesn't implement Cloneable");
    }

    return internalClone();

    }
    克隆方法:創(chuàng)建并返回此對(duì)象的副本;
    對(duì)于任何對(duì)象x x.clone()!=x
    而且x.clone().getClass()==x.getClass() 成立 雖然對(duì)象的基類(lèi)都支持clone 但是object本身并未實(shí)現(xiàn)cloneable,所以自定義的類(lèi)需要實(shí)現(xiàn)cloneable接口,否則將拋出異常

  4. toString()
    返回對(duì)象的字符串表示形式,一般說(shuō)來(lái),這個(gè)方法返回一個(gè)固定的模版public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    這個(gè)在實(shí)際開(kāi)發(fā)中,并不好體現(xiàn),所以各大編譯器都支持 重新生成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()方法可以被子類(lèi)對(duì)象所覆蓋,然后作為一個(gè)終結(jié)者,當(dāng)GC被調(diào)用的時(shí)候完成最后的清理工作(例如釋放系統(tǒng)資源之類(lèi))。這就是終止。默認(rèn)的finalize()方法什么也不做,當(dāng)被調(diào)用時(shí)直接返回。
      對(duì)于任何一個(gè)對(duì)象,它的finalize()方法都不會(huì)被JVM執(zhí)行兩次。如果你想讓一個(gè)對(duì)象能夠被再次調(diào)用的話(huà)(例如,分配它的引用給一個(gè)靜態(tài)變量),注意當(dāng)這個(gè)對(duì)象已經(jīng)被GC回收的時(shí)候,finalize()方法不會(huì)被調(diào)用第二次。測(cè)試:
      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í)行了一次
  6. wait()? notify() notifyAll()
    這三個(gè)方法是有關(guān)線(xiàn)程阻塞與線(xiàn)程喚醒
  7. wait(),notify()與notifyAll()方法是本地方法,并且是final類(lèi)型,無(wú)法重寫(xiě)
  8. 調(diào)用某個(gè)對(duì)象的wait()方法能讓當(dāng)前線(xiàn)程阻塞,并且當(dāng)前線(xiàn)程必須擁有此對(duì)象的monitor(即鎖)
  9. 調(diào)用某個(gè)對(duì)象的notify()方法能喚醒一個(gè)正在等待這個(gè)對(duì)象的monitor的線(xiàn)程,如果有多個(gè)線(xiàn)程在等待這個(gè)monitor,喚醒其中一個(gè)線(xiàn)程;
  10. 調(diào)用notifyAll()方法能喚醒所有正在等待這個(gè)對(duì)象的monitor為何這三個(gè)不是Thread類(lèi)聲明中的方法,而是Object類(lèi)中聲明的方法(當(dāng)然由于Thread類(lèi)繼承了Object類(lèi),所以Thread也可以調(diào)用者三個(gè)方法)?其實(shí)這個(gè)問(wèn)題很簡(jiǎn)單,由于每個(gè)對(duì)象都擁有monitor(即鎖),所以讓當(dāng)前線(xiàn)程等待某個(gè)對(duì)象的鎖,當(dāng)然應(yīng)該通過(guò)這個(gè)對(duì)象來(lái)操作了。而不是用當(dāng)前線(xiàn)程來(lái)操作,因?yàn)楫?dāng)前線(xiàn)程可能會(huì)等待多個(gè)線(xiàn)程的鎖,如果通過(guò)線(xiàn)程來(lái)操作,就非常復(fù)雜了。
      上面已經(jīng)提到,如果調(diào)用某個(gè)對(duì)象的wait()方法,當(dāng)前線(xiàn)程必須擁有這個(gè)對(duì)象的monitor(即鎖),因此調(diào)用wait()方法必須在同步塊或者同步方法中進(jìn)行(synchronized塊或者synchronized方法)。
      調(diào)用某個(gè)對(duì)象的wait()方法,相當(dāng)于讓當(dāng)前線(xiàn)程交出此對(duì)象的monitor,然后進(jìn)入等待狀態(tài),等待后續(xù)再次獲得此對(duì)象的鎖(Thread類(lèi)中的sleep方法使當(dāng)前線(xiàn)程暫停執(zhí)行一段時(shí)間,從而讓其他線(xiàn)程有機(jī)會(huì)繼續(xù)執(zhí)行,但它并不釋放對(duì)象鎖);
      notify()方法能夠喚醒一個(gè)正在等待該對(duì)象的monitor的線(xiàn)程,當(dāng)有多個(gè)線(xiàn)程都在等待該對(duì)象的monitor的話(huà),則只能喚醒其中一個(gè)線(xiàn)程,具體喚醒哪個(gè)線(xiàn)程則不得而知。
      同樣地,調(diào)用某個(gè)對(duì)象的notify()方法,當(dāng)前線(xiàn)程也必須擁有這個(gè)對(duì)象的monitor,因此調(diào)用notify()方法必須在同步塊或者同步方法中進(jìn)行(synchronized塊或者synchronized方法)?! ofityAll()方法能夠喚醒所有正在等待該對(duì)象的monitor的線(xiàn)程,這一點(diǎn)與notify()方法是不同的。
      這里要注意一點(diǎn):notify()和notifyAll()方法只是喚醒等待該對(duì)象的monitor的線(xiàn)程,并不決定哪個(gè)線(xiàn)程能夠獲取到monitor。
      舉個(gè)簡(jiǎn)單的例子:假如有三個(gè)線(xiàn)程Thread1、Thread2和Thread3都在等待對(duì)象objectA的monitor,此時(shí)Thread4擁有對(duì)象objectA的monitor,當(dāng)在Thread4中調(diào)用objectA.notify()方法之后,Thread1、Thread2和Thread3只有一個(gè)能被喚醒。注意,被喚醒不等于立刻就獲取了objectA的monitor。假若在Thread4中調(diào)用objectA.notifyAll()方法,則Thread1、Thread2和Thread3三個(gè)線(xiàn)程都會(huì)被喚醒,至于哪個(gè)線(xiàn)程接下來(lái)能夠獲取到objectA的monitor就具體依賴(lài)于操作系統(tǒng)的調(diào)度了。
      上面尤其要注意一點(diǎn),一個(gè)線(xiàn)程被喚醒不代表立即獲取了對(duì)象的monitor,只有等調(diào)用完notify()或者notifyAll()并退出synchronized塊,釋放對(duì)象鎖后,其余線(xiàn)程才可獲得鎖執(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("線(xiàn)程" + Thread.currentThread().getName() + "開(kāi)始");
    synchronized (obj) {
    try {
    System.out.println("線(xiàn)程" + Thread.currentThread().getName() + "調(diào)用了object.wait()");
    obj.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("線(xiàn)程" + Thread.currentThread().getName() + "獲取到了鎖");
    }
    }
    }
    static class Thread2 extends Thread {@Override
    br/>@Override
    super.run();
    System.out.println("線(xiàn)程" + Thread.currentThread().getName() + "開(kāi)始");
    synchronized (obj) {
    obj.notify();
    System.out.println("線(xiàn)程" + Thread.currentThread().getName() + "調(diào)用了object.notify()");
    }
    System.out.println("線(xiàn)程" + Thread.currentThread().getName() + "釋放了鎖");
    }
    }
    }運(yùn)行結(jié)果:線(xiàn)程Thread-0開(kāi)始
    線(xiàn)程Thread-1開(kāi)始
    線(xiàn)程Thread-0調(diào)用了object.wait()
    線(xiàn)程Thread-1調(diào)用了object.notify()
    線(xiàn)程Thread-1釋放了鎖
    線(xiàn)程Thread-0獲取到了鎖
    Process finished with exit code 0
    1、Object類(lèi)的七大native方法:registerNatives()、getClass()、hashCode()、clone()、notify()、notifyAll()、wait(long)native關(guān)鍵字修飾的方法稱(chēng)為本地方法,這些方法并不是用java實(shí)現(xiàn)的,考慮到實(shí)現(xiàn)的性能問(wèn)題,大多是由C/C++編寫(xiě)的程序,編譯成dll文件,再由java去加載這些dll文件,就可以通過(guò)java來(lái)調(diào)用dll中的函數(shù)了1)registerNatives()方法:主要是將用C/C++語(yǔ)言寫(xiě)的一些方法,如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()方法:我們可以看到這個(gè)方法是由final修飾的,因此不能被重寫(xiě)的,對(duì)final關(guān)鍵字不太了解的,可以看一下我的另一篇文章:Java源碼解析之 final關(guān)鍵字的使用詳解//class 是一個(gè)類(lèi)的屬性,能獲取該類(lèi)編譯時(shí)的類(lèi)對(duì)象
    System.out.println(Bird.class);//class com.somta.test.commonuseobj.objectobj.Bird//getClass() 是一個(gè)類(lèi)的方法,它是獲取該類(lèi)運(yùn)行時(shí)的類(lèi)對(duì)象
    System.out.println(bird.getClass());//class com.somta.test.commonuseobj.objectobj.Bird
    3)hashCode()方法:返回一個(gè)整數(shù)的HashCode值,該值依賴(lài)于內(nèi)部表示堆的對(duì)象的指針,一般情況下,該方法都會(huì)被重寫(xiě)。關(guān)于hashCode與equals的關(guān)系,我們只需要記住下面四句話(huà)(前提:需要重寫(xiě)equals和hashCode方法,String、Integer、Boolean、Double等都重寫(xiě)了這兩個(gè)方法,不重寫(xiě)HashCode方法,任何對(duì)象的hashCodeZFX返傭www.fx61.com/brokerlist/zfx.html都是不相等的,并且equals方法也會(huì)使用Object中的equals方法,此時(shí)equals和==是等價(jià)的,equals比較的是棧中的引用,而非對(duì)象的值)1、如果兩個(gè)對(duì)象相等,則它們的hashCode值一定相等
    2、如果兩個(gè)對(duì)象不相等,則它們的hashCode值不一定都不相等
    3、如果兩個(gè)對(duì)象的hashCode值相等,兩個(gè)對(duì)象不一定相等
    4、如果兩個(gè)對(duì)象的hashCode值不相等,兩個(gè)對(duì)象一定不相等4)clone()方法: 將一個(gè)對(duì)象克隆出一個(gè)新對(duì)象,要實(shí)現(xiàn)clone的對(duì)象一般需要先實(shí)現(xiàn)Cloneable接口才能達(dá)到克隆的目的,克隆其實(shí)也分“淺克隆”,“深克隆” ,Object類(lèi)的克隆屬于“淺克隆”,關(guān)于克隆的知識(shí),后續(xù)在寫(xiě)文章說(shuō)明,此處就不展開(kāi)了5)notify()、notifyAll()、wait(long)方法: 這些方法后續(xù)在多線(xiàn)程中在具體講解2、Object類(lèi)的常用方法:equals()、toString()
    1)、equals()方法我們可能在以前的面試中被問(wèn)到過(guò)關(guān)于 == 和 equals的區(qū)別,可能大多人的回答是:“==運(yùn)算符通常是用來(lái)比較基本類(lèi)型的值是否相等或者比較對(duì)象的引用是否相等;equals比較的是兩個(gè)對(duì)象是否相等”,這種說(shuō)法其實(shí)并不太正確,不妨我們先看Object中關(guān)于equals()方法的源碼public boolean equals(Object obj) {
    return (this == obj);
    }
    Object類(lèi)是所有類(lèi)的子類(lèi),如果一個(gè)類(lèi)沒(méi)有重寫(xiě)equals()方法,那它就會(huì)使用父類(lèi)的的equals()方法,通過(guò)上面的代碼可以看出其實(shí)在Object類(lèi)中,==運(yùn)算符和equals()方法是等價(jià)的,其實(shí)上面的說(shuō)法只適用于那些重寫(xiě)了Object類(lèi)equals方法的類(lèi)而言是正確的,比如String等。注意:重寫(xiě)equals()方法的時(shí)候,必須要重寫(xiě)hashCode方法,以維護(hù)hashCode的約束,確保equals()方法聲明相等的對(duì)象具有相同的hashCode值2)、toString()方法public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    getClass().getName()返回了該類(lèi)的全類(lèi)名,Integer.toHexString(hashCode())返回了以16進(jìn)制無(wú)符號(hào)整數(shù)的形式返回了此hashCode的字符串,這個(gè)是根類(lèi)Object的實(shí)現(xiàn),子類(lèi)中一般都會(huì)重寫(xiě)該方法
向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI