<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    類和對象的初始化

    類的生命周期:分為裝載,鏈接,初始化
    如圖:


    1)裝載:查找并裝載類型的二進(jìn)制數(shù)據(jù)
    2)連接:執(zhí)行驗證,準(zhǔn)備,和解析(可選)
             a) 驗證:確保導(dǎo)入類型正確
             b) 準(zhǔn)備:為類變量分配內(nèi)存,并將其初始化為默認(rèn)值
             c) 解析:把類型中的符號引用轉(zhuǎn)換成直接引用
    3)初始化:把類變量初始化為默認(rèn)初值


          隨著Java虛擬機(jī)裝載了一個類,并執(zhí)行了一些它選擇進(jìn)行的驗證之后,類就可以進(jìn)入準(zhǔn)備階
    段了。在準(zhǔn)備階段,Java虛擬機(jī)為類變量分配內(nèi)存,設(shè)置默認(rèn)初始值:但在到達(dá)初始化階段之前,
    類變量都沒有被初始化為真正的初始值。(在準(zhǔn)備階段是不會執(zhí)行Java代碼的。)在準(zhǔn)備階段,虛
    擬機(jī)把給類變量新分配的內(nèi)存根據(jù)類型設(shè)置為默認(rèn)值。

     為了準(zhǔn)備讓一個類或者接口被"首次主動"使用,最后一個步驟就是初始化,也就是為類變量      
    賦予正確的初始值。這里的”正確”初始值指的是程序員希望這個類變量所具備的起始值。正
    確的初始值是和在準(zhǔn)備階段賦予的默認(rèn)初始值對比而言的。前面說過,根據(jù)類型的不同,類變
    量已經(jīng)被賦予了默認(rèn)初始值。而正確的初始值是根據(jù)程序員制定的主觀計劃面生成的。


    在Java代碼中,一個正確的初始值是通過類變量初始化語句或者靜態(tài)初始化語句給出的。
     1)一個類變量初始化語句是變量聲明后面的等號和表達(dá)式:
     2)靜態(tài)初始化語句是一個以static開頭的程序塊
     example : 
        public class Example1 {
         
         // 類變量初始化語句
         static int value = (int) (Math.random()*6.0);
         
         // 靜態(tài)初始化語句
         static{
          System.out.println("this is example");
         }
        }
    所有的類變量初始化語句和類型的靜態(tài)初始化器都被Java編譯器收集在—起,放到——個特殊
    的方法中。對于類來說,這個方法被稱作類初始化方法;對于接口來說,它被稱為接口初始化
    方法。在類和接口的Javaclass文件中,這個方法被稱為”<clinit>”。通常的Java程序方法是無法
    調(diào)用這個<clinit>方法的。這種方法只能被Java虛擬機(jī)調(diào)用

    clinit>()方法
        前面說過,Java編譯器把類變量初始化語句和靜態(tài)初始化浯句的代碼都放到class文件的
    <clinit>()方法中,順序就按照它們在類或者接門聲明中出現(xiàn)的順序。
     example:
      public class Example1 {
        static int width;
        static int height = (int) (Math.random()*6.0);

        static{
         width = (int) (Math.random()*3.0);
        }
     }
    java 編譯器生成下面<clinit>方法:
    0 invokestatic java.lang.Math.random
    3 ldc2_w 6.0 (double)
    6 dmul
    7 d2i
    8 putstatic Example1.height
    11 invokestatic java.lang.Math.random
    14 ldc2_w 3.0 (double) 17 dmul
    18 d2i
    19 putstatic Example1.width
    22 return

    clinit 方法首先執(zhí)行唯一的類變量初始化語句初始化heght,然后在靜態(tài)初始化語句中
    初始化width(雖然它聲明在height之前,但那僅僅是聲明了類變量而不是類變量初始化語句).

     

    除接口以外,初始化一個類之前必須保證其直接超類已被初始化,并且該初始化過程是由 Jvm 保證線程安全的。
    另外,并非所有的類都會擁有一個 <clinit>() 方法。
    1)如果類沒有聲明任何類變量,也沒有靜態(tài)初始化語句,那么它不會有<clinit>()方法。
    2)如果聲明了類變量但是沒有使用類變量初始化語句或者靜態(tài)初始化語句初始它們,那么類不會有<clinit>()方法。 
       example:
          public class example{
           static int val;
          }
        
    3)如果類僅包含靜態(tài) final 變量的類變量初始化語句,并且類變量初始化語句是編譯時常量表達(dá)式,類不會有<clinit>()方法。
        example:
        public class Example {
         static final String str ="abc";
         static final int value = 100;
        }
    這種情況java編譯器把 str 和 value 被看做是常量,jvm會直接使用該類的常量池或者在字節(jié)碼中直接存放常量值。該類不會被加載。
     
    如果接口不包含在編譯時解析成常量的字段初始化語句,接口中就包含一個<clinit>()方法。
    example:
     interface Example{
      int i =5;
      int hoursOfSleep = (int) (Math.random()*3.0);
      
     }
    字段hoursOfSleep會被放在<clinit>()方法中(比較詭異???它被看作類變量了),而字段i被看作是編譯時常量特殊處理(JAVA語法規(guī)定,接口中的變量默認(rèn)自動隱含是public static final)。
     java 編譯器生成下面<clinit>方法:
    0 invokestatic java.lang.Math.random
    3 ldc2_w 3.0 (double)
    6 dmul
    7 d2i
    8 putstatic Example.hoursOfSleep
    11 return

    主動使用和被動使用
        在前面講過,Java虛擬機(jī)在首次主動使用類型時初始化它們。只有6種活動被認(rèn)為是主動使
    用:
     1)創(chuàng)建類的新實(shí)例,
     2)調(diào)用類中聲明的靜態(tài)方法,
     3)操作類或者接口中聲明的非常量靜態(tài)字段,
     4)調(diào)用JavaAPI中特定的反射方法
     5)初始化一個類的子類;
     6)以及指定一個類作為Java虛擬機(jī)啟動時的初始化類。
     
       使用一個非常量的靜態(tài)字段只有當(dāng)類或者接口的確聲明了這個字段時才是主動使用、比如,
    類中聲明的字段可能會被子類引用;接口中聲明的字段可能會被子接口或者實(shí)現(xiàn)了這個接口的
    類引用。對于子類、子接口和實(shí)現(xiàn)接口的類來說.這就是被動使用(使用它們并不會觸發(fā)
    它們的初始化)。下面的例子說明了這個原理:

    class NewParement{
     static int hoursOfSleep = (int) (Math.random()*3.0);
     
     static{
      System.out.println("new parement is initialized.");
     }
    }

    class NewbornBaby extends NewParement{
     static int hoursOfCry = (int) (Math.random()*2.0);
     
     static{
      System.out.println("new bornBaby is initialized.");
     }
    }


    public class Example1 {
     
     public static void main(String[] args){
      int hours = NewbornBaby.hoursOfSleep;
      System.out.println(hours);
     }
     static{
      System.out.println("example1 is initialized.");
     }
     
    }
    運(yùn)行結(jié)果:
    example1 is initialized.
    new parement is initialized.
    0
    NewbornBaby 沒有被初始化,也沒有被加載。


    對象的生命周期

            當(dāng)java虛擬機(jī)創(chuàng)建一個新的類實(shí)例時不管明確的還是隱含的,首先要在堆中為保存對象的實(shí)例變量分配內(nèi)存,包含所有在對象類中和它超類中
    聲明的變量(包括隱藏的實(shí)例變量)都要分配內(nèi)存。其次賦默認(rèn)初值,最后賦予正確的初始值。

    java編譯器為每個類都至少生成一個實(shí)例初始化方法 "<init>()"與構(gòu)造方法相對應(yīng)。

    如果構(gòu)造方法調(diào)用同一個類中的另一個構(gòu)造方法(構(gòu)造方法重載),它對應(yīng)的init<>():
    1)一個同類init<>()調(diào)用。
    2)對應(yīng)構(gòu)造方法體代碼的調(diào)用。
    如果構(gòu)造方法不是通過this()調(diào)用開始,且對象不是Object 它對應(yīng)的init<>():
    1)一個超類init<>()調(diào)用。
    2)任意實(shí)例變量初始化代碼調(diào)用。
    3)對應(yīng)構(gòu)造方法體代碼的調(diào)用。
    如果上述對象是Object,則去掉第一條。如果構(gòu)造方法明確使用super()首先調(diào)用對應(yīng)超類init<>()其余不變。
    下面的例子詳細(xì)說明了實(shí)例變量初始化(摘自Java Language Specification)
    class Point{
     int x,y;
     Point(){x=1;y=1;}
    }
    class ColoredPoint extends Point{
     int color = OxFF00FF;
    }
    class Test{
     public static void main(String[] args){
      ColoredPoint cp = new ColoredPoint();
      System.out.println(cp.color);
     }
    }
    首先,為新的ColoredPoint實(shí)例分配內(nèi)存空間,以存儲實(shí)例變量x,y和color;然后將這些變量初始化成默認(rèn)值
    在這個例子中都是0。
    接下來調(diào)用無參數(shù)的ColoredPoint(),由于ColorPoint沒有聲明構(gòu)造方法,java編譯器會自動提供如下的構(gòu)造方
    法:ColoredPoint(){super();}。
    該構(gòu)造方法然后調(diào)用無參數(shù)的Point(),而Point()沒有顯示的超類,編譯器會提供一個對其無參數(shù)的構(gòu)造方法的
    隱式調(diào)用:Point(){super();x=1;y=1}。
    因此將會調(diào)用到Object();Object類沒有超類,至此遞歸調(diào)用會終止。接下來會調(diào)用Object任何實(shí)例初始化語句
    及任何實(shí)例變量初始化語句。
    接著執(zhí)行Object()由于Object類中未聲明這樣的構(gòu)造方法。因此編譯器會提供默認(rèn)的構(gòu)造方法object(){}。
    但是執(zhí)行該構(gòu)造方法不會產(chǎn)生任何影響,然后返回。
    接下來執(zhí)行Point類實(shí)例變量初始化語句。當(dāng)這個過程發(fā)生時,x,y的聲明沒有提供任何初始化表達(dá)式,因此這個
    步驟未采取任何動作(x,y 仍為0);
    接下來執(zhí)行Point構(gòu)造方法體,將x,y賦值為1。
    接下來會執(zhí)行類ColoredPoint的實(shí)例變量初始化語句。把color賦值0xFF00FF,最后執(zhí)行ColoredPoint構(gòu)造方法體
    余下的部分(super()調(diào)用之后的部分),碰巧沒有任何語句,因此不需要進(jìn)一步的動作,初始化完成。

    與C++不同的是,在創(chuàng)建新的類實(shí)例期間,java編程語言不會為方法分派來指定變更的規(guī)則。如果調(diào)用的方法在被
    初始化對象的子類中重寫,那么就是用重寫的方法。甚至新對象被完全初始化前也是如此。編譯和運(yùn)行下面的例子
    class Super{
     Super(){printThree();}
     void printThree{System.out.println("Three");}
    }
    class Test extends Super{
     int three = (int)Math.PI; // That is 3
     public static void main(String args[]){
      Test t = new Test();
      t.printThree();
     }
     void printThree(){System.out.println(three);}
    }
    輸出:
    0
    3
    這表明Super類中的printThree()沒有被執(zhí)行。而是調(diào)用的Test中的printThree()。

     

     
     

    posted on 2010-07-14 16:18 AK47 閱讀(895) 評論(0)  編輯  收藏 所屬分類: java相關(guān)

    <2010年7月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導(dǎo)航

    統(tǒng)計

    常用鏈接

    留言簿

    隨筆分類

    隨筆檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 久久亚洲国产成人精品无码区| 国产精品免费看久久久香蕉 | 亚洲乱码国产乱码精华| 亚洲色精品88色婷婷七月丁香 | 激情无码亚洲一区二区三区| 亚洲日本在线看片| 国产国拍精品亚洲AV片| 全亚洲最新黄色特级网站| aa级一级天堂片免费观看| 51视频精品全部免费最新| 成人无码a级毛片免费| 黄页网站在线观看免费| 欧美激情综合亚洲一二区| 亚洲 欧洲 日韩 综合在线| 337p日本欧洲亚洲大胆色噜噜| 亚洲国产第一站精品蜜芽| 久久精品国产亚洲5555| 亚洲乱码中文字幕综合234| 免费在线视频一区| 免费亚洲视频在线观看| 国产精品jizz在线观看免费| 全免费a级毛片免费**视频| 女人被弄到高潮的免费视频| A在线观看免费网站大全| 最近最新的免费中文字幕| 西西大胆无码视频免费| 免费观看AV片在线播放| 在线看片免费不卡人成视频| 97在线观看永久免费视频| 无码精品A∨在线观看免费| 国产人成免费视频网站| 99久久99这里只有免费费精品| 成人免费的性色视频| 日本成年免费网站| 久久精品无码一区二区三区免费| 三年片在线观看免费观看高清电影| 色se01短视频永久免费| 免费一本色道久久一区| 蜜桃精品免费久久久久影院| 宅男666在线永久免费观看| 免费a级毛片18以上观看精品|