欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java源碼解析之object類

 更新時(shí)間:2017年10月24日 16:38:36   作者:青樓有罪  
前些天看到別人討論閱讀源碼有什么用這個(gè)問題,有一句話說的特別好:學(xué)習(xí)別人實(shí)現(xiàn)某個(gè)功能的設(shè)計(jì)思路,來提高自己的編程水平。本文主要介紹了Java源碼解析之object類,需要的朋友可以參考。

在源碼的閱讀過程中,可以了解別人實(shí)現(xiàn)某個(gè)功能的涉及思路,看看他們是怎么想,怎么做的。接下來,我們看看這篇Java源碼解析之object的詳細(xì)內(nèi)容。

Java基類Object

  java.lang.Object,Java所有類的父類,在你編寫一個(gè)類的時(shí)候,若無指定父類(沒有顯式extends一個(gè)父類)編譯器(一般編譯器完成該步驟)會(huì)默認(rèn)的添加Object為該類的父類(可以將該類反編譯看其字節(jié)碼,不過貌似Java7自帶的反編譯javap現(xiàn)在看不到了)。

  再說的詳細(xì)點(diǎn):假如類A,沒有顯式繼承其他類,編譯器會(huì)默認(rèn)添加Object為其父類;若有,那么那個(gè)顯式父類呢?要么是沒有顯式繼承,那么Object是這個(gè)父類的父類,那肯定也是類A的父類,如果有,以此類推,所以,Object是Java所有類的祖先類(父類)。

聲明

  1.本系列是JDK1.7(oracle)的源碼分析,若和你查看到的源碼有差異,請(qǐng)對(duì)比JDK版本。

  2.本系列是本人對(duì)Java源碼的解析,但由于本人水平有限,勢(shì)必不能做到完全解讀,甚至只能說通過搜索閱讀學(xué)習(xí),做一些表面的解析,有不足之處,望指教,望諒解。

Object源碼

public class Object {
 //本地方法,C/C++在DLL中實(shí)現(xiàn),通過JNI調(diào)用
 private static native void registerNatives();
 //類初始化調(diào)用此方法
 static {
  registerNatives();
 }
 //返回此Object的運(yùn)行時(shí)類(每個(gè)類的Class類對(duì)象)
 public final native Class<?> getClass();
 //獲得該對(duì)象的hash值
 public native int hashCode();
 //對(duì)比兩對(duì)象的內(nèi)存地址,如果不重寫,equals方法比較的是對(duì)象地址
 public boolean equals(Object obj) {
  return (this == obj);
 }
 //本地clone方法,用于對(duì)象的賦值
 protected native Object clone() throws CloneNotSupportedException;
 //返回對(duì)象的的字符串表示,默認(rèn)是:類名+@+hash值
 public String toString() {
  return getClass().getName() + "@" + Integer.toHexString(hashCode());
 //notify()/notifyAll()/wait()以及wait兩個(gè)重載方法都是線程同步相關(guān)方法
 public final native void notify();
 public final native void notifyAll();
 public final native void wait(long timeout) throws InterruptedException;
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);
 }
 public final void wait() throws InterruptedException {
  wait(0);
 }
 //對(duì)象被回收時(shí)調(diào)用,不管如何,一個(gè)對(duì)象只調(diào)用一次
 protected void finalize() throws Throwable { }

概述

  因?yàn)镺bject是Java所有類的祖先類,所以Java所有類都有Object中的方法,在看這些方法的時(shí)候要聯(lián)系這些方法不是針對(duì)Objec一個(gè)類,而是所有類。

  既然是所有類共有,設(shè)計(jì)的時(shí)候肯定想的是所有類的共性,比如:equals方法就是用來比較任意兩個(gè)相同類型對(duì)象是否相等的,toString是用來將任意對(duì)象轉(zhuǎn)換成String,方便打印查看。當(dāng)然,以上方法的實(shí)現(xiàn)都是默認(rèn)的,想要實(shí)現(xiàn)自己的邏輯需要在自己類中覆蓋重寫。

  以上的native方法,在Oracle的jdk是看不到的,但在OpenJDK或其他開源JDK是可以找到對(duì)應(yīng)的C/C++代碼的。
源碼詳解

1.構(gòu)造方法

  源碼中并沒有Object的構(gòu)造方法,但是,同樣的,編譯器在編譯期間會(huì)給Object(事實(shí)上,所有的Java類,只要類中沒有構(gòu)造方法,編譯器都會(huì)默認(rèn)的給一個(gè)空構(gòu)造方法,若已有構(gòu)造方法,則不會(huì)添加)一個(gè)默認(rèn)的空的構(gòu)造方法:

public Object(){}

2.registerNatives

  帶有native修飾的都是本地方法,所謂的本地方法是不通過Java語言實(shí)現(xiàn)的方法,但可以通過JNI,像調(diào)用Java方法一樣調(diào)用這些方法。詳細(xì)的可以搜索查看JNI。

  這個(gè)方法的作用是對(duì)Object以下幾個(gè)本地方法(hashCode/clone/notify等)進(jìn)行注冊(cè)(可以理解為,這個(gè)方法是告訴JVM這幾個(gè)本地方法的實(shí)現(xiàn)映射),每一個(gè)有本地方法的都會(huì)有這個(gè)方法,但其內(nèi)容不一樣(因?yàn)樽?cè)的方法不一樣嘛)。

3.getClass

  每一個(gè)類在被加載的時(shí)候,都會(huì)生成一個(gè)Class類實(shí)例,而這個(gè)方法就可以在運(yùn)行時(shí)期獲得對(duì)象(這里的對(duì)象是堆里的那個(gè)對(duì)象,也就是獲得的是動(dòng)態(tài)類型的那個(gè)類)的Class對(duì)象,Class對(duì)象主要用于反射。

class A{}
class B extends A{}
class C extends B{}
A a = new C();//對(duì)象new C()的靜態(tài)類型是A,動(dòng)態(tài)類型是C
B b = (B)a;//引用b指向的還是new C(),動(dòng)態(tài)類型還是C
C c = (C)b;
System.out.println(a.getClass().getName());
System.out.println(b.getClass().getName());
System.out.println(c.getClass().getName());
//打印結(jié)果均是:com.xxx.test.C
//對(duì)象的動(dòng)態(tài)類型是不會(huì)變的,即new后面那個(gè)類型(構(gòu)造對(duì)象的那個(gè)類型),但是靜態(tài)類
//型是由指向它的引用決定的,事實(shí)上可以這樣理解對(duì)象只有動(dòng)態(tài)類型,引用類型才是靜態(tài)類型
//以上說的對(duì)象指的是堆里對(duì)象,而不是泛指Object o = new Object()中的o
//不明白靜態(tài)類型,動(dòng)態(tài)類型的可以自行百度

4.hashCode

  獲得該對(duì)象的hash值,Java虛擬機(jī)規(guī)范并沒有規(guī)定這個(gè)方法的具體實(shí)現(xiàn),只是規(guī)定了同一個(gè)對(duì)象兩次調(diào)用(任何條件情形下)這個(gè)方法返回的int值要想等(但并沒有規(guī)定兩個(gè)不同對(duì)象hash值一定不相同),具體實(shí)現(xiàn)由各個(gè)JVM廠商自己實(shí)現(xiàn),所以返回的值意義并不一定(這里特指Object的hashCode方法),有可能返回的是對(duì)象的內(nèi)存地址,也有可能是某個(gè)特定計(jì)算公式計(jì)算出來的值。

5.equals

  原則上或則說語義上,設(shè)計(jì)目的上,equals的作用意義,是用來比較兩個(gè)對(duì)象是否相等,這里是我們通常理解的相等:即兩個(gè)對(duì)象其內(nèi)容是否相等,而不是程序上來看,兩個(gè)對(duì)象是否是同一個(gè)對(duì)象,即比較其內(nèi)存地址;如果想比較兩個(gè)對(duì)象是否是同一個(gè)對(duì)象(這里是說兩個(gè)引用是否指向同一個(gè)對(duì)象),直接用==比較即可(==比較的就是對(duì)象的內(nèi)存地址)。但這里重要的是,對(duì)于Object來說,它并不能知道子類是如何判斷他們的兩個(gè)實(shí)例是如何equals的,所以,默認(rèn)的equals實(shí)現(xiàn),比較的是兩對(duì)象內(nèi)存地址,即,若子類不重寫equals方法,其作用等同于==。

//如何重寫equals方法實(shí)現(xiàn)判斷內(nèi)容相等?
//關(guān)鍵點(diǎn)取決于你的邏輯,你想讓兩個(gè)對(duì)象在什么時(shí)候相等,你邏輯上就怎么寫
class A {
 public int a;
 public String b;
 public D d;

 @Override
 public boolean equals(Object o) {
  if (this == o) return true;//如果指向同一個(gè)對(duì)象,當(dāng)然equals
  //如果o為null或兩個(gè)對(duì)象類型都不相同,當(dāng)然不equals
  if (o == null || getClass() != o.getClass()) return false;
  //動(dòng)態(tài)類型相同,強(qiáng)制轉(zhuǎn)換
  A a1 = (A) o;
  /*下面是自己的邏輯,判斷兩個(gè)對(duì)象是否相同,邏輯1 Begin*/
  if (a != a1.a) return false;
  if (b != null ? !b.equals(a1.b) : a1.b != null) return false;
  return d != null ? d.equals(a1.d) : a1.d == null;
  //全部字段相同,則equals。如果對(duì)象越復(fù)雜,想要實(shí)現(xiàn)全部字段相同,也就越復(fù)雜
  /* 邏輯1 End */
  /* 邏輯2 begin*/
  //只要字段a相同,就認(rèn)為兩個(gè)對(duì)象equals
  if(a == a1.a) return true;
  /* 邏輯2 end*/
 }
 @Override
 public int hashCode() {
  int result = a;
  result = 31 * result + (b != null ? b.hashCode() : 0);
  result = 31 * result + (d != null ? d.hashCode() : 0);
  return result;
 }
}
class D{
 public int a;
}

  網(wǎng)上說的,重寫equals方法,必重寫hashCode,其實(shí)不然,若確定所有地方都沒有用到類似Map的地方,就不必重寫hashCode,因?yàn)镸ap的諸多方法是有用到hashCode方法判斷兩對(duì)象是否相等,而若你僅僅是自己用來判斷兩個(gè)對(duì)象是否equals,也就不必重寫hashCode(當(dāng)然,還要確定其他地方不會(huì)用到hashCode的地方,比如,以后用,別人用等,不過一般的,推薦重寫hashCode方法,這樣保證任何地方都不會(huì)因此出錯(cuò))。

  若hash值不相等,則兩個(gè)對(duì)象肯定不等(不equals);

  若hash值相等,兩個(gè)對(duì)象不一定相等(不一定equals)。

  equals相等,hash值肯定想等,也就是說,hash值相等時(shí)equals相等的必要條件。

  hashCode方法一般用來判斷兩個(gè)對(duì)象equals前置條件,用來排除,這樣做的原因是,hashCode方法速度快,不相等的可快速否決掉,若hash相同,則再調(diào)用equals判斷。

6.clone

  克隆對(duì)象,克隆一個(gè)與原先對(duì)象所有字段值相等的對(duì)象,從而獲得一個(gè)新的對(duì)象,需要注意的是:

想要使用這個(gè)方法,對(duì)象類型必須實(shí)現(xiàn)Cloneable接口,否則會(huì)報(bào)錯(cuò),原因是Object的clone方法有對(duì)對(duì)象類型驗(yàn)證,如沒實(shí)現(xiàn)則報(bào)錯(cuò)拋異常;

clone方法返回的是一個(gè)新的對(duì)象,這個(gè)對(duì)象的創(chuàng)建不是通過new(除非你像下面那樣不通過Object的clone方法重寫)指令,而是JVM通過其他指令創(chuàng)建的;

clone有深度clone和淺clone,這主要是針對(duì)類中間具有引用類型而言劃分的,詳情可參看:Java clone深度解析。

class A{}
A a = new A();
a.clone();//報(bào)錯(cuò),即拋CloneNotSupportedException異常
class A implements Cloneable{}//這樣才不會(huì)
//但,若你重寫clone方法,并且在這個(gè)方法中沒有調(diào)用父clone(也就是Object)方法
class A{
 @Override
 public Object clone() throws CloneNotSupportedException{
  return new A();
 }
}
a.clone();//這個(gè)時(shí)候調(diào)用clone方法即使沒有實(shí)現(xiàn)Cloneable方法也不會(huì)報(bào)錯(cuò)
//說白了,你要理解為什么調(diào)用clone方法要實(shí)現(xiàn)Cloneable的原因,而不是僅僅是記住
//當(dāng)你理解了,你就能熟練掌握這些規(guī)則,而不是記住他們

7.toString

  toString這個(gè)方法算是Object比較常用的方法了,它的意義是提供將類的字段以String形式格式化輸出這一功能,當(dāng)然,同樣的,Object不可能知道子類的字段信息,所以,默認(rèn)toString輸出的是:全路徑類名+@+hash值。

  若你想要輸出類的字段信息,需要重寫toString方法,將該類字段信息以你自己的格式輸出。

8.notify/notifyAll/wait

  這三個(gè)方法適用于線程同步,這里只簡(jiǎn)單介紹其作用,詳細(xì)請(qǐng)參考:notify/notifyAll/wait。

  notify:隨機(jī)喚醒等待(wait)隊(duì)列中一個(gè)對(duì)象,使其需要該對(duì)象的線程繼續(xù)執(zhí)行;

  notifyAll:?jiǎn)拘殃?duì)列中所有對(duì)象

  wait:該對(duì)象陷入等待狀態(tài),需要該對(duì)象的線程將不能再繼續(xù)執(zhí)行,直到該對(duì)象由其他線程調(diào)用notify/notifyAll方法喚醒。

9.finalize

  在對(duì)象被GC(垃圾回收,詳情可參考:Java GC概述)之前被調(diào)用(JVM主動(dòng)調(diào)用),你可以重寫這個(gè)方法,然后在這個(gè)對(duì)象回收之前做某些動(dòng)作,這個(gè)方法對(duì)于這個(gè)對(duì)象來說只能調(diào)用一次,為什么會(huì)這么說呢?對(duì)象都回收了,沒了,難道不是當(dāng)然只能調(diào)用一次?不是這樣的,若你理解了Java GC原理便知道,若當(dāng)你在finalize方法中,將這個(gè)對(duì)象重新賦予了強(qiáng)引用,GC這個(gè)對(duì)象將失敗,這個(gè)對(duì)象將繼續(xù)存活,而下次這個(gè)對(duì)象又成為可回收對(duì)象了,GC回收這個(gè)對(duì)象的時(shí)候,這個(gè)對(duì)象的finalize方法將不會(huì)再執(zhí)行。

  另外,需要區(qū)分的是:

  finalize不是C/C++中的析構(gòu)函數(shù),更不是釋放內(nèi)存的方法,它只是提供了在回收一個(gè)對(duì)象之前做某些操作,如果你熟悉C ,那你知道C 允許你為一個(gè)類定義一個(gè)撤消函數(shù)(destructor ),它在對(duì)象正好出作用域之前被調(diào)用。Java不支持這個(gè)想法也不提供撤消函數(shù)。finalize() 方法只和撤消函數(shù)的功能接近。當(dāng)你對(duì)Java 有豐富經(jīng)驗(yàn)時(shí),你將看到因?yàn)镴ava使用垃圾回收子系統(tǒng),幾乎沒有必要使用撤消函數(shù)。

  而且,在設(shè)計(jì)之初,這個(gè)方法就是為了兼容C/C++程序員習(xí)慣(對(duì)的,貌似就是這樣),后來設(shè)計(jì)者也說,這是個(gè)失敗的設(shè)計(jì),所以,可以的話,在實(shí)踐中忘掉這個(gè)方法吧。

class D{
 public static D d111;

 @Override
 protected void finalize() throws Throwable {
  super.finalize();
  d111 = this;//這個(gè)時(shí)候該對(duì)象第一次回收將失敗,而以后將不會(huì)在執(zhí)行該方法
  System.out.println("finalize a = " + this.a);
 }
}
D d = new D();
d = null;
//程序結(jié)束
//這個(gè)時(shí)候,雖然程序結(jié)束了,new D()對(duì)象也是可回收對(duì)象了,但是并不會(huì)執(zhí)行
//finzlize,因?yàn)閷?duì)于JVM來說GC的觸發(fā)條件是內(nèi)存不足,所以不會(huì)執(zhí)行GC也就不會(huì)調(diào)用
//finzlize方法

總結(jié)

以上就是本文關(guān)于Java源碼解析之object類的全部內(nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:java.lang.Void類源碼解析淺談Java多線程處理中Future的妙用(附源碼)等,有什么問題可以隨時(shí)留言,小編會(huì)及時(shí)回復(fù)大家的。感謝朋友們對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java中幾個(gè)Reference常見的作用詳解

    Java中幾個(gè)Reference常見的作用詳解

    這篇文章主要給大家介紹了Java中關(guān)于Reference多個(gè)作用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)吧。
    2017-06-06
  • 在SpringBoot框架下實(shí)現(xiàn)Excel導(dǎo)入導(dǎo)出的方法詳解

    在SpringBoot框架下實(shí)現(xiàn)Excel導(dǎo)入導(dǎo)出的方法詳解

    SpringBoot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開發(fā)過程,今天我們就使用純前對(duì)按表格控件帶大家了解,如何在Spring Boot框架下實(shí)現(xiàn)Excel服務(wù)端導(dǎo)入導(dǎo)出,需要的朋友可以參考下
    2023-06-06
  • SpringBoot條件注解@Conditional詳細(xì)解析

    SpringBoot條件注解@Conditional詳細(xì)解析

    這篇文章主要介紹了SpringBoot條件注解@Conditional詳細(xì)解析,@Conditional是Spring4.0提供的一個(gè)用于條件裝配的注解,其定義了一個(gè)Condition的數(shù)組,只有當(dāng)數(shù)組所有的條件都滿足的時(shí)候,組件才會(huì)被導(dǎo)入容器,需要的朋友可以參考下
    2023-11-11
  • java compiler沒有1.8怎么解決

    java compiler沒有1.8怎么解決

    這篇文章主要介紹了java compiler沒有1.8的解決方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-08-08
  • 基于java查找最長字符串代碼實(shí)例

    基于java查找最長字符串代碼實(shí)例

    這篇文章主要介紹了基于java查找最長字符串代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Spring之Environment類的使用方式

    Spring之Environment類的使用方式

    這篇文章主要介紹了Spring之Environment類的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Java編程實(shí)現(xiàn)生成給定范圍內(nèi)不重復(fù)隨機(jī)數(shù)的方法小結(jié)

    Java編程實(shí)現(xiàn)生成給定范圍內(nèi)不重復(fù)隨機(jī)數(shù)的方法小結(jié)

    這篇文章主要介紹了Java編程實(shí)現(xiàn)生成給定范圍內(nèi)不重復(fù)隨機(jī)數(shù)的方法,結(jié)合實(shí)例形式總結(jié)分析了java基于數(shù)學(xué)運(yùn)算與判斷實(shí)現(xiàn)不重復(fù)隨機(jī)數(shù)的生成功能,需要的朋友可以參考下
    2017-07-07
  • spring使用JavaConfig進(jìn)行配置的方法

    spring使用JavaConfig進(jìn)行配置的方法

    這篇文章主要介紹了spring使用JavaConfig進(jìn)行配置的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09
  • 詳解Feign的實(shí)現(xiàn)原理

    詳解Feign的實(shí)現(xiàn)原理

    Feign是Netflix開發(fā)的聲明式、模板化的HTTP客戶端, Feign可以幫助我們更快捷、優(yōu)雅地調(diào)用HTTP API
    2021-06-06
  • Mybatis分頁插件PageHelper手寫實(shí)現(xiàn)示例

    Mybatis分頁插件PageHelper手寫實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了Mybatis分頁插件PageHelper手寫實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08

最新評(píng)論