欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Java之object類的示例分析

這篇文章給大家分享的是有關(guān)Java之object類的示例分析的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來(lái)看看吧。

創(chuàng)新互聯(lián)公司是一家專注于成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)與策劃設(shè)計(jì),市中網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)公司做網(wǎng)站,專注于網(wǎng)站建設(shè)十余年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:市中等地區(qū)。市中做網(wǎng)站價(jià)格咨詢:028-86922220

Java基類Object

java.lang.Object,Java所有類的父類,在你編寫一個(gè)類的時(shí)候,若無(wú)指定父類(沒有顯式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方法就是用來(lái)比較任意兩個(gè)相同類型對(duì)象是否相等的,toString是用來(lái)將任意對(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語(yǔ)言實(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ì)算出來(lái)的值。

5.equals

原則上或則說語(yǔ)義上,設(shè)計(jì)目的上,equals的作用意義,是用來(lái)比較兩個(gè)對(duì)象是否相等,這里是我們通常理解的相等:即兩個(gè)對(duì)象其內(nèi)容是否相等,而不是程序上來(lái)看,兩個(gè)對(duì)象是否是同一個(gè)對(duì)象,即比較其內(nèi)存地址;如果想比較兩個(gè)對(duì)象是否是同一個(gè)對(duì)象(這里是說兩個(gè)引用是否指向同一個(gè)對(duì)象),直接用==比較即可(==比較的就是對(duì)象的內(nèi)存地址)。但這里重要的是,對(duì)于Object來(lái)說,它并不能知道子類是如何判斷他們的兩個(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ì)象是否相等,而若你僅僅是自己用來(lái)判斷兩個(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方法一般用來(lái)判斷兩個(gè)對(duì)象equals前置條件,用來(lái)排除,這樣做的原因是,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ì)象來(lái)說只能調(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ì)的,貌似就是這樣),后來(lái)設(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來(lái)說GC的觸發(fā)條件是內(nèi)存不足,所以不會(huì)執(zhí)行GC也就不會(huì)調(diào)用
//finzlize方法

感謝各位的閱讀!關(guān)于“Java之object類的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

網(wǎng)站欄目:Java之object類的示例分析
URL分享:http://www.chinadenli.net/article12/pesegc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司網(wǎng)站排名外貿(mào)建站企業(yè)網(wǎng)站制作定制開發(fā)動(dòng)態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)