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

java繼承關(guān)系的類初始化和實(shí)例化順序是怎樣的

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)java繼承關(guān)系的類初始化和實(shí)例化順序是怎樣的,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

創(chuàng)新互聯(lián)建站是一家專業(yè)提供茄子河企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)成都h5網(wǎng)站建設(shè)、小程序制作等業(yè)務(wù)。10年已為茄子河眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進(jìn)行中。

就像之前的一個(gè)評(píng)論.我們學(xué)習(xí)的是思路. 很多人都知道繼承關(guān)系的類的初始化和實(shí)例化的順序,但如果忘記了怎么辦? 如何找到自己的答案? 又如果遇到的問(wèn)題是關(guān)于泛型的擦除問(wèn)題,又該如何去分析?

思路,重點(diǎn)是思路.泛型擦除先不談.看繼承. 首先給出一個(gè)例子,看看它的輸出是什么.

public class A {      private static String a = "NA";      private String i="NA";      {          i = "A";          System.out.println(i);      }            static {          a = "Static A";          System.out.println(a);      }            public A() {          System.out.println("Construct A");      }  }
public class B extends A {      private static String b = "NB";      private String j="NB";      {          j = "B";          System.out.println(j);      }            static {          b = "Static B";          System.out.println(b);      }            public B() {          System.out.println("Construct B");      }  }
public class C {      public static void main(String[] args) {          new B();      }   }

以上輸出是:

Static A
Static B
A
Construct A
B
Construct B

一切都是java編譯器搞得鬼. JVM只是負(fù)責(zé)解析字節(jié)碼.字節(jié)碼雖然不是最原始的原子匯編碼,但字節(jié)碼已經(jīng)可以完全解釋JVM的指令執(zhí)行過(guò)程了.一般來(lái)說(shuō),字節(jié)碼和java源碼相差比較大,javac會(huì)做前期優(yōu)化,修改增加刪除源碼產(chǎn)生jvm解釋器可以理解的字節(jié)碼. java語(yǔ)法帶來(lái)的安全,易用,易讀等功能讓我們忽略了字節(jié)碼會(huì)和java源碼有出路.

當(dāng)遇到new的時(shí)候,比如new B(),將會(huì)嘗試去初始化B類.如果B已經(jīng)初始化,則開(kāi)始實(shí)例化B類.如果B類沒(méi)有初始化,則初始化B類,但B類繼承A,所以在初始化B類之前需要先初始化A類.所以類的初始化過(guò)程是:A->B. 類在初始化的時(shí)候會(huì)執(zhí)行static域和塊. 類的實(shí)例化在類初始化之后,實(shí)例化的時(shí)候必須先實(shí)例化父類.實(shí)例化會(huì)先執(zhí)行域和塊,然后再執(zhí)行構(gòu)造函數(shù).

上面的理論如果靠這種死記硬背,總會(huì)忘記.哦,還有父類的構(gòu)造函數(shù)必須放在子類構(gòu)造函數(shù)的***行.為什么?

遇到這種語(yǔ)法問(wèn)題的時(shí)候,看教科書(shū)不如自己找出答案.工具就在JDK中,一個(gè)名叫javap的命令. javap會(huì)打出一個(gè)class的字節(jié)碼偽碼. 我們只需要分析B的字節(jié)碼,就可以找到答案.

joeytekiMacBook-Air:bin joey$ javap -verbose B  Compiled from "B.java" public class B extends A    SourceFile: "B.java"   minor version: 0   major version: 50   Constant pool:  const #1 = class    #2; //  B  const #2 = Asciz    B;  const #3 = class    #4; //  A  const #4 = Asciz    A;  const #5 = Asciz    b;  const #6 = Asciz    Ljava/lang/String;;  const #7 = Asciz    j;  const #8 = Asciz    <clinit>;  const #9 = Asciz    ()V;  const #10 = Asciz   Code;  const #11 = String  #12;    //  NB  const #12 = Asciz   NB;  const #13 = Field   #1.#14; //  B.b:Ljava/lang/String;  const #14 = NameAndType #5:#6;//  b:Ljava/lang/String;  const #15 = String  #16;    //  Static B  const #16 = Asciz   Static B;  const #17 = Field   #18.#20;    //  java/lang/System.out:Ljava/io/PrintStream;  const #18 = class   #19;    //  java/lang/System  const #19 = Asciz   java/lang/System;  const #20 = NameAndType #21:#22;//  out:Ljava/io/PrintStream;  const #21 = Asciz   out;  const #22 = Asciz   Ljava/io/PrintStream;;  const #23 = Method  #24.#26;    //  java/io/PrintStream.println:(Ljava/lang/String;)V  const #24 = class   #25;    //  java/io/PrintStream  const #25 = Asciz   java/io/PrintStream;  const #26 = NameAndType #27:#28;//  println:(Ljava/lang/String;)V  const #27 = Asciz   println;  const #28 = Asciz   (Ljava/lang/String;)V;  const #29 = Asciz   LineNumberTable;  const #30 = Asciz   LocalVariableTable;  const #31 = Asciz   <init>;  const #32 = Method  #3.#33; //  A."<init>":()V  const #33 = NameAndType #31:#9;//  "<init>":()V  const #34 = Field   #1.#35; //  B.j:Ljava/lang/String;  const #35 = NameAndType #7:#6;//  j:Ljava/lang/String;  const #36 = String  #2; //  B  const #37 = String  #38;    //  Construct B  const #38 = Asciz   Construct B;  const #39 = Asciz   this;  const #40 = Asciz   LB;;  const #41 = Asciz   SourceFile;  const #42 = Asciz   B.java;   {  static {};    Code:     Stack=2, Locals=0, Args_size=0    0:   ldc #11; //String NB     2:   putstatic   #13; //Field b:Ljava/lang/String;     5:   ldc #15; //String Static B     7:   putstatic   #13; //Field b:Ljava/lang/String;     10:  getstatic   #17; //Field java/lang/System.out:Ljava/io/PrintStream;     13:  getstatic   #13; //Field b:Ljava/lang/String;     16:  invokevirtual   #23; //Method java/io/PrintStream.println:(Ljava/lang/String;)V     19:  return   LineNumberTable:      line 3: 0    line 11: 5    line 12: 10    line 13: 19    public B();    Code:     Stack=2, Locals=1, Args_size=1    0:   aload_0     1:   invokespecial   #32; //Method A."<init>":()V     4:   aload_0     5:   ldc #11; //String NB     7:   putfield    #34; //Field j:Ljava/lang/String;     10:  aload_0     11:  ldc #36; //String B     13:  putfield    #34; //Field j:Ljava/lang/String;     16:  getstatic   #17; //Field java/lang/System.out:Ljava/io/PrintStream;     19:  aload_0     20:  getfield    #34; //Field j:Ljava/lang/String;     23:  invokevirtual   #23; //Method java/io/PrintStream.println:(Ljava/lang/String;)V     26:  getstatic   #17; //Field java/lang/System.out:Ljava/io/PrintStream;     29:  ldc #37; //String Construct B     31:  invokevirtual   #23; //Method java/io/PrintStream.println:(Ljava/lang/String;)V     34:  return   LineNumberTable:      line 15: 0    line 4: 4    line 6: 10    line 7: 16    line 16: 26    line 17: 34    LocalVariableTable:      Start  Length  Slot  Name   Signature     0      35      0    this       LB;  }

類的生命周期,將經(jīng)歷類的裝載,鏈接,初始化,使用,卸載. 裝載是將字節(jié)碼讀入到內(nèi)存的方法區(qū)中, 而類的初始化則會(huì)在線程棧中執(zhí)行static{}塊的code. 在之前,這個(gè)塊有另一個(gè)名字<cinit>即類初始化方法.現(xiàn)在改名為static{}了. 類的初始化只進(jìn)行一次. 但是,每當(dāng)一個(gè)類在裝載和鏈接完畢以后,通過(guò)字節(jié)碼的分析,JVM解析器已經(jīng)知道B是繼承A的,于是在初始化B類前,A類會(huì)先初始化.這是一個(gè)遞歸過(guò)程. 所以,B類的初始化會(huì)導(dǎo)致A類static{}執(zhí)行,然后是B的static{}執(zhí)行.讓我們看看B的static{}塊中執(zhí)行了什么.

static {};    Code:     Stack=2, Locals=0, Args_size=0 棧深為2,本地變量0個(gè),參數(shù)傳遞0個(gè).     0:   ldc #11; //String NB  將常量池中#11放到棧頂.#11="NB".     2:   putstatic   #13; //Field b:Ljava/lang/String;  將棧頂?shù)闹?nbsp;"NB" 賦予常量池中的#13,也就是 static b="NB".     5:   ldc #15; //String Static B  將#15放入棧頂. #15="static B".     7:   putstatic   #13; //Field b:Ljava/lang/String;  賦值static b = "static B".     10:  getstatic   #17; //Field java/lang/System.out:Ljava/io/PrintStream;  將PrintStream引用壓棧.     13:  getstatic   #13; //Field b:Ljava/lang/String;  將static b的值壓棧.     16:  invokevirtual   #23; //Method java/io/PrintStream.println:(Ljava/lang/String;)V  調(diào)用虛函數(shù)PrintStream.println("static B")     19:  return 退出函數(shù),銷毀函數(shù)棧幀.

通過(guò)注釋,我們看到類B中的static域賦值和static塊均被放到了類的初始化函數(shù)中.

當(dāng)我們進(jìn)行類的實(shí)例化的時(shí)候,會(huì)調(diào)用類的構(gòu)造函數(shù).我們看看類B的構(gòu)造函數(shù)做了什么.

public B();    Code:     Stack=2, Locals=1, Args_size=1 棧深為2,本地變量1個(gè)(其實(shí)就是this),參數(shù)為1個(gè)(就是this).     0:   aload_0  將***個(gè)參數(shù)壓棧.也就是this壓棧.     1:   invokespecial   #32; //Method A."<init>":()V  在this上調(diào)用父類的構(gòu)造函數(shù).在B的構(gòu)造函數(shù)中并沒(méi)有聲明super(),但是java編譯器會(huì)自動(dòng)生成此字節(jié)碼來(lái)調(diào)用父類的無(wú)參構(gòu)造函數(shù).如果在B類中聲明了super(int),編譯器會(huì)使用對(duì)應(yīng)的A類構(gòu)造函數(shù)來(lái)代替.JVM只是執(zhí)行字節(jié)碼而已,它并不對(duì)super進(jìn)行約束,約束它們的是java的編譯器.this出棧.     4:   aload_0  將this壓棧.     5:   ldc #11; //String NB  將"NB"壓棧.     7:   putfield    #34; //Field j:Ljava/lang/String;  給j賦值this.j="NB". this和"NB"出棧.     10:  aload_0  將this壓棧.     11:  ldc #36; //String B  把"B"壓棧     13:  putfield    #34; //Field j:Ljava/lang/String;  給j賦值this.j="B". this和"B"出棧.棧空     16:  getstatic   #17; //Field java/lang/System.out:Ljava/io/PrintStream;  壓棧PrintStream     19:  aload_0  壓棧this    20:  getfield    #34; //Field j:Ljava/lang/String;  this出棧,調(diào)用this.j,壓棧this.j.     23:  invokevirtual   #23; //Method java/io/PrintStream.println:(Ljava/lang/String;)V  調(diào)用PrintStream.println(this.j).棧空.     26:  getstatic   #17; //Field java/lang/System.out:Ljava/io/PrintStream;  壓棧PrintStream     29:  ldc #37; //String Construct B  壓棧"Construct B"    31:  invokevirtual   #23; //Method java/io/PrintStream.println:(Ljava/lang/String;)V  調(diào)用PrintStream.println("Construct B")     34:  return

從上面的字節(jié)碼可以看出,java編譯器在編譯產(chǎn)生字節(jié)碼的時(shí)候,將父類的構(gòu)造函數(shù),域的初始化,代碼塊的執(zhí)行和B的真正的構(gòu)造函數(shù)按照順序組合在了一起,形成了新的構(gòu)造函數(shù). 一個(gè)類的編譯后的構(gòu)造函數(shù)字節(jié)碼一定會(huì)遵循這樣的順序包含以下內(nèi)容:

父類的構(gòu)造函數(shù)->

當(dāng)前類的域初始化->(按照書(shū)寫(xiě)順序)

代碼塊->(按照書(shū)寫(xiě)順序)

當(dāng)前類的構(gòu)造函數(shù).

到這里,應(yīng)該徹底明白繼承類的初始化和實(shí)例化順序了.

上述就是小編為大家分享的java繼承關(guān)系的類初始化和實(shí)例化順序是怎樣的了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

本文題目:java繼承關(guān)系的類初始化和實(shí)例化順序是怎樣的
網(wǎng)頁(yè)路徑:http://chinadenli.net/article28/gshgjp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃域名注冊(cè)定制網(wǎng)站小程序開(kāi)發(fā)品牌網(wǎng)站設(shè)計(jì)標(biāo)簽優(yōu)化

廣告

聲明:本網(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)

綿陽(yáng)服務(wù)器托管