一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Java源碼解析之object類

Java源碼解析之object類

2021-01-24 11:37青樓有罪 Java教程

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

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

Java基類Object

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

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

聲明

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

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

Object源碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Object {
 //本地方法,C/C++在DLL中實(shí)現(xiàn),通過JNI調(diào)用
 private static native void registerNatives();
 //類初始化調(diào)用此方法
 static {
  registerNatives();
 }
 //返回此Object的運(yùn)行時類(每個類的Class類對象)
 public final native Class<?> getClass();
 //獲得該對象的hash值
 public native int hashCode();
 //對比兩對象的內(nèi)存地址,如果不重寫,equals方法比較的是對象地址
 public boolean equals(Object obj) {
  return (this == obj);
 }
 //本地clone方法,用于對象的賦值
 protected native Object clone() throws CloneNotSupportedException;
 //返回對象的的字符串表示,默認(rèn)是:類名+@+hash值
 public String toString() {
  return getClass().getName() + "@" + Integer.toHexString(hashCode());
 //notify()/notifyAll()/wait()以及wait兩個重載方法都是線程同步相關(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);
 }
 //對象被回收時調(diào)用,不管如何,一個對象只調(diào)用一次
 protected void finalize() throws Throwable { }

概述

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

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

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

1.構(gòu)造方法

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

?
1
public Object(){}

2.registerNatives

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

  這個方法的作用是對Object以下幾個本地方法(hashCode/clone/notify等)進(jìn)行注冊(可以理解為,這個方法是告訴JVM這幾個本地方法的實(shí)現(xiàn)映射),每一個有本地方法的都會有這個方法,但其內(nèi)容不一樣(因?yàn)樽缘姆椒ú灰粯勇铮?/p>

3.getClass

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A{}
class B extends A{}
class C extends B{}
A a = new C();//對象new C()的靜態(tài)類型是A,動態(tài)類型是C
B b = (B)a;//引用b指向的還是new C(),動態(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
//對象的動態(tài)類型是不會變的,即new后面那個類型(構(gòu)造對象的那個類型),但是靜態(tài)類
//型是由指向它的引用決定的,事實(shí)上可以這樣理解對象只有動態(tài)類型,引用類型才是靜態(tài)類型
//以上說的對象指的是堆里對象,而不是泛指Object o = new Object()中的o
//不明白靜態(tài)類型,動態(tài)類型的可以自行百度

4.hashCode

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

5.equals

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//如何重寫equals方法實(shí)現(xiàn)判斷內(nèi)容相等?
//關(guān)鍵點(diǎn)取決于你的邏輯,你想讓兩個對象在什么時候相等,你邏輯上就怎么寫
class A {
 public int a;
 public String b;
 public D d;
 
 @Override
 public boolean equals(Object o) {
  if (this == o) return true;//如果指向同一個對象,當(dāng)然equals
  //如果o為null或兩個對象類型都不相同,當(dāng)然不equals
  if (o == null || getClass() != o.getClass()) return false;
  //動態(tài)類型相同,強(qiáng)制轉(zhuǎn)換
  A a1 = (A) o;
  /*下面是自己的邏輯,判斷兩個對象是否相同,邏輯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。如果對象越復(fù)雜,想要實(shí)現(xiàn)全部字段相同,也就越復(fù)雜
  /* 邏輯1 End */
  /* 邏輯2 begin*/
  //只要字段a相同,就認(rèn)為兩個對象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方法判斷兩對象是否相等,而若你僅僅是自己用來判斷兩個對象是否equals,也就不必重寫hashCode(當(dāng)然,還要確定其他地方不會用到hashCode的地方,比如,以后用,別人用等,不過一般的,推薦重寫hashCode方法,這樣保證任何地方都不會因此出錯)。

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

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

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

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

6.clone

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

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

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

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

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

7.toString

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

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

8.notify/notifyAll/wait

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

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

  notifyAll:喚醒隊(duì)列中所有對象

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

9.finalize

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class D{
 public static D d111;
 
 @Override
 protected void finalize() throws Throwable {
  super.finalize();
  d111 = this;//這個時候該對象第一次回收將失敗,而以后將不會在執(zhí)行該方法
  System.out.println("finalize a = " + this.a);
 }
}
D d = new D();
d = null;
//程序結(jié)束
//這個時候,雖然程序結(jié)束了,new D()對象也是可回收對象了,但是并不會執(zhí)行
//finzlize,因?yàn)閷τ贘VM來說GC的觸發(fā)條件是內(nèi)存不足,所以不會執(zhí)行GC也就不會調(diào)用
//finzlize方法

總結(jié)

以上就是本文關(guān)于Java源碼解析之object類的全部內(nèi)容,希望對大家有所幫助。有什么問題可以隨時留言,小編會及時回復(fù)大家的。感謝朋友們對服務(wù)器之家網(wǎng)站的支持!

原文鏈接:http://blog.csdn.net/a327369238/article/details/52490359

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品久久久久久 | 四虎最新永久在线精品免费 | 99看视频| www.日日爱 | 免费观看日本人成影片 | 成人操| 国产精品国产精品国产三级普 | 亚洲国产成人久久综合一区 | 国产福利微拍精品一区二区 | 星空传媒在线视频 | 国内久久婷婷综合欲色啪 | 福利国模私拍视频在线观看 | 国产欧美日韩精品一区二区三区 | 国产一级真人毛爱做毛片 | 国产良心大作白丝精厕 | 千金肉奴隶免费观看 | 欧美一区二区三区精品 | 日日视频 | 秘书小说 | 国产福利不卡视频 | 奇米影视先锋 | 白丝爆动漫羞羞动漫软件 | www.羞羞视频 | 国产成人精品日本亚洲网址 | 我与岳乱短篇小说 | 国产91精品在线观看 | 99久久精品国产片久人 | 黄网久久 | 视频免费观看在线播放高清 | 亚洲a视频在线 | 人禽l交免费视频观看+视频 | 日韩欧美中文字幕一区二区三区 | 爽好舒服宝贝添奶吻戏 | caopren免费视频国产 | 日韩免费一级片 | 国产视频分类 | 免费理伦片高清在线 | 国产馆精品推荐在线观看 | 超级乱淫伦小说1女多男 | 色婷婷综合缴情综六月 | 暖暖视频高清图片免费完整版 |