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

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

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

    一路拾遺
    Collect By Finding All The Way ......
    posts - 81,comments - 41,trackbacks - 0
        可以這樣認(rèn)為,每個(gè)類都有一個(gè)名為Initialize()的方法,這個(gè)名字就暗示了它得在使用之前調(diào)用,不幸的是,這么做的話,用戶就得記住要調(diào)用這個(gè)方法,java類庫(kù)的設(shè)計(jì)者們可以通過(guò)一種被稱為構(gòu)造函數(shù)的特殊方法,來(lái)保證每個(gè)對(duì)象都能得到被始化.如果類有構(gòu)造函數(shù),那么java就會(huì)在對(duì)象剛剛創(chuàng)建,用戶還來(lái)不及得到的時(shí)候,自動(dòng)調(diào)用那個(gè)構(gòu)造函數(shù),這樣初始化就有保障了。

    我不知道原作者的描述和譯者的理解之間有多大的差異,結(jié)合全章,我沒(méi)有發(fā)現(xiàn)兩個(gè)最關(guān)鍵的字""和""。至少說(shuō)明原作者和譯者并沒(méi)有真正說(shuō)明JVM在初始 化時(shí)做了什么,或者說(shuō)并不了解JVM的初始化內(nèi)幕,要不然明明有這兩個(gè)方法,卻為什么要認(rèn)為有一個(gè)事實(shí)上并不存在的"Initialize()"方法呢?

    ""和""方法在哪里?這兩個(gè)方法是實(shí)際存在而你又找不到的方法,也許正是這樣才使得一些大師都犯暈。加上jdk實(shí)現(xiàn)上的一些BUG,如果沒(méi)有深入了解,真的讓人摸不著北。

    現(xiàn)在科學(xué)體系有一個(gè)奇怪的現(xiàn)象,那么龐大的體系最初都是建立在一個(gè)假設(shè)的基礎(chǔ)是,假設(shè)1是正確的,由此推導(dǎo)出2,再繼續(xù)推導(dǎo)出10000000000。 可惜的是太多的人根本不在乎2-100000000000這樣的體系都是建立在假設(shè)1是正確的基礎(chǔ)上的。我并不會(huì)用“可以這樣認(rèn)為”這樣的假設(shè),我要確實(shí) 證明""和""方法是真真實(shí)實(shí)的存在的:

    package debug;
    public class MyTest{
    static int i = 100/0;
    public static void main(String[] args){
    Ssytem.out.println("Hello,World!");
    }
    }

      執(zhí)行一下看看,這是jdk1.5的輸出:

    java.lang.ExceptionInInitializerError
    Caused by: java.lang.ArithmeticException: / by zero
    at debug.MyTest.(Test.java:3)
    Exception in thread "main"

      請(qǐng)注意,和其它方法調(diào)用時(shí)產(chǎn)生的異常一樣,異常被定位于debug.MyTest的.

    再來(lái)看:

    package debug;
    public class Test {
    Test(){
    int i = 100 / 0;
    }
    public static void main(String[] args) {
    new Test();
    }
    }


      jdk1.5輸入:

    Exception in thread "main" java.lang.ArithmeticException: / by zero

    at debug.Test.(Test.java:4)

    at debug.Test.main(Test.java:7)

    JVM并沒(méi)有把異常定位在Test()構(gòu)造方法中,而是在debug.Test.。

    當(dāng)我們看到了這兩個(gè)方法以后,我們?cè)賮?lái)詳細(xì)討論這兩個(gè)“內(nèi)置初始化方法”(我并不喜歡生造一些非標(biāo)準(zhǔn)的術(shù)語(yǔ),但我確實(shí)不知道如何規(guī)范地稱呼他們)。

    內(nèi)置初始化方法是JVM在內(nèi)部專門用于初始化的特有方法,而不是提供給程序員調(diào)用的方法,事實(shí)上“<>”這樣的語(yǔ)法在源程序中你連編譯都無(wú)法通過(guò)。這就說(shuō)明,初始化是由JVM控制而不是讓程序員來(lái)控制的。

    類初始化方法:

    我沒(méi)有從任何地方了解到的cl是不是class的簡(jiǎn)寫,但這個(gè)方法確實(shí)是用來(lái)對(duì)“類”進(jìn)行初始化的。換句話說(shuō)它是用來(lái)初始化static上下文的。

    在類裝載(load)時(shí),JVM會(huì)調(diào)用內(nèi)置的方法對(duì)類成員和靜態(tài)初始化塊進(jìn)行初始化調(diào)用。它們的順序按照源文件的原文順序。

    我們稍微增加兩行static語(yǔ)句:

    package debug;
    public class Test {
    static int x = 0;
    static String s = "123";
    static {
    String s1 = "456";
    if(1==1)
    throw new RuntimeException();
    }
    public static void main(String[] args) {
    new Test();
    }
    }

      然后進(jìn)行反編譯:

    javap -c debug.Test
    Compiled from "Test.java"
    public class debug.Test extends java.lang.Object{
    static int x;
    static java.lang.String s;
    public debug.Test();
    Code:
    0: aload_0
    1: invokespecial #1; //Method java/lang/Object."":()V
    4: return
    public static void main(java.lang.String[]);
    Code:
    0: new #2; //class debug/Test
    3: dup
    4: invokespecial #3; //Method "":()V
    7: pop
    8: return
    static {};
    Code:
    0: iconst_0
    1: putstatic #4; //Field x:I
    4: ldc #5; //String 123
    6: putstatic #6; //Field s:Ljava/lang/String;
    9: ldc #7; //String 456
    11: astore_0
    12: new #8; //class java/lang/RuntimeException
    15: dup
    16: invokespecial #9; //Method java/lang/RuntimeException."":()V
    19: athrow
    }

      我們可以看到,類初始化正是按照源文件中定義的原文順序進(jìn)行。先是聲明

    static int x;
    static java.lang.String s;

      然后對(duì)int x和String s進(jìn)行賦值:

    0: iconst_0
    1: putstatic #4; //Field x:I
    4: ldc #5; //String 123
    6: putstatic #6; //Field s:Ljava/lang/String;

      執(zhí)行初始化塊的String s1 = "456";生成一個(gè)RuntimeException拋

    9: ldc #7; //String 456
    11: astore_0
    12: new #8; //class java/lang/RuntimeException
    15: dup
    16: invokespecial #9; //Method java/lang/RuntimeException."":()V
    19: athrow

      要明白的是,""方法不僅是類初始化方法,而且也是接口初始化方法。并不是所以接口

    的屬性都是內(nèi)聯(lián)的,只有直接賦常量值的接口常量才會(huì)內(nèi)聯(lián)。而

    [public static final] double d = Math.random()*100;

    這樣的表達(dá)式是需要計(jì)算的,在接口中就要由""方法來(lái)初始化。

    下面我們?cè)賮?lái)看看實(shí)例初始化方法""

    ""用于對(duì)象創(chuàng)建時(shí)對(duì)對(duì)象進(jìn)行初始化,當(dāng)在HEAP中創(chuàng)建對(duì)象時(shí),一旦在HEAP分配了空間。最先就會(huì)調(diào)用""方法。這個(gè)方法包括實(shí)例變量的賦值(聲明 不在其中)和初始化塊,以及構(gòu)造方法調(diào)用。如果有多個(gè)重載的構(gòu)造方法,每個(gè)構(gòu)造方法都會(huì)有一個(gè)對(duì)應(yīng)的""方法。構(gòu)造方法隱式或顯示調(diào)用父類的構(gòu)造方法前, 總是先執(zhí)行實(shí)例變量初始化和初始化塊.同樣,實(shí)例變量和初始化塊的順序也是按源文件的原文順序執(zhí)行,構(gòu)造方法中的代碼在最后執(zhí)行:

    package debug;
    public class Test {
    int x = 0;
    String s = "123";
    {
    String s1 = "456";
    //if(1==1)
    //throw new RuntimeException();
    }
    public Test(){
    String ss = "789";
    }
    public static void main(String[] args) {
    new Test();
    }
    }
    javap -c debug.Test的結(jié)果:
    Compiled from "Test.java"
    public class debug.Test extends java.lang.Object{
    int x;
    java.lang.String s;
    public debug.Test();
    Code:
    0: aload_0
    1: invokespecial #1; //Method java/lang/Object."":()V
    4: aload_0
    5: iconst_0
    6: putfield #2; //Field x:I
    9: aload_0
    10: ldc #3; //String 123
    12: putfield #4; //Field s:Ljava/lang/String;
    15: ldc #5; //String 456
    17: astore_1
    18: ldc #6; //String 789
    20: astore_1
    21: return
    public static void main(java.lang.String[]);
    Code:
    0: new #7; //class debug/Test
    3: dup
    4: invokespecial #8; //Method "":()V
    7: pop
    8: return
    }


      如果在同一個(gè)類中,一個(gè)構(gòu)造方法調(diào)用了另一個(gè)構(gòu)造方法,那么對(duì)應(yīng)的""方法就會(huì)調(diào)用另一個(gè)"",但是實(shí)例變量和初始化塊會(huì)被忽略,否則它們就會(huì)被多次執(zhí)行。

    package debug;
    public class Test {
    String s1 = rt("s1");
    String s2 = "s2";
    public Test(){
    s1 = "s1";
    }
    public Test(String s){
    this();
    if(1==1) throw new Runtime();
    }
    String rt(String s){
    return s;
    }
    public static void main(String[] args) {
    new Test("");
    }
    }

      反編譯的結(jié)果:

    Compiled from "Test.java"
    public class debug.Test extends java.lang.Object{
    java.lang.String s1;
    java.lang.String s2;
    public debug.Test();
    Code:
    0: aload_0
    1: invokespecial #1; //Method java/lang/Object."":()V
    4: aload_0
    5: aload_0
    6: ldc #2; //String s1
    8: invokevirtual #3; //Method rt:(Ljava/lang/String;)Ljava/lang/String;
    11: putfield #4; //Field s1:Ljava/lang/String;
    14: aload_0
    15: ldc #5; //String s2
    17: putfield #6; //Field s2:Ljava/lang/String;
    20: aload_0
    21: ldc #2; //String s1
    23: putfield #4; //Field s1:Ljava/lang/String;
    26: return
    public debug.Test(java.lang.String);
    Code:
    0: aload_0
    1: invokespecial #7; //Method "":()V
    4: new #8; //class java/lang/RuntimeException
    7: dup
    8: invokespecial #9; //Method java/lang/RuntimeException."":()V
    11: athrow
    java.lang.String rt(java.lang.String);
    Code:
    0: aload_1
    1: areturn
    public static void main(java.lang.String[]);
    Code:
    0: new #10; //class debug/Test
    3: dup
    4: ldc #11; //String
    6: invokespecial #12; //Method "":(Ljava/lang/String;)V
    9: pop
    10: return
    }

      我們看到,由于Test(String s)調(diào)用了Test();所以"":(Ljava/lang/String;)V不再對(duì)實(shí)例變量和初始化塊進(jìn)次初始化:

    public debug.Test(java.lang.String);
    Code:
    0: aload_0
    1: invokespecial #7; //Method "":()V
    4: new #8; //class java/lang/RuntimeException
    7: dup
    8: invokespecial #9; //Method java/lang/RuntimeException."":()V
    11: athrow

      而如果兩個(gè)構(gòu)造方法是相互獨(dú)立的,則每個(gè)構(gòu)造方法調(diào)用前都會(huì)執(zhí)行實(shí)例變量和初始化塊的調(diào)用:

    package debug;
    public class Test {
    String s1 = rt("s1");
    String s2 = "s2";
    {
    String s3 = "s3";
    }
    public Test() {
    s1 = "s1";
    }
    public Test(String s) {
    if (1 == 1)
    throw new RuntimeException();
    }
    String rt(String s) {
    return s;
    }
    public static void main(String[] args) {
    new Test("");
    }
    }

      反編譯的結(jié)果:

    Compiled from "Test.java"
    public class debug.Test extends java.lang.Object{
    java.lang.String s1;
    java.lang.String s2;
    public debug.Test();
    Code:
    0: aload_0
    1: invokespecial #1; //Method java/lang/Object."":()V
    4: aload_0
    5: aload_0
    6: ldc #2; //String s1
    8: invokevirtual #3; //Method rt:(Ljava/lang/String;)Ljava/lang/String;
    11: putfield #4; //Field s1:Ljava/lang/String;
    14: aload_0
    15: ldc #5; //String s2
    17: putfield #6; //Field s2:Ljava/lang/String;
    20: ldc #7; //String s3
    22: astore_1
    23: aload_0
    24: ldc #2; //String s1
    26: putfield #4; //Field s1:Ljava/lang/String;
    29: return
    public debug.Test(java.lang.String);
    Code:
    0: aload_0
    1: invokespecial #1; //Method java/lang/Object."":()V
    4: aload_0
    5: aload_0
    6: ldc #2; //String s1
    8: invokevirtual #3; //Method rt:(Ljava/lang/String;)Ljava/lang/String;
    11: putfield #4; //Field s1:Ljava/lang/String;
    14: aload_0
    15: ldc #5; //String s2
    17: putfield #6; //Field s2:Ljava/lang/String;
    20: ldc #7; //String s3
    22: astore_2
    23: new #8; //class java/lang/RuntimeException
    26: dup
    27: invokespecial #9; //Method java/lang/RuntimeException."":()V
    30: athrow
    java.lang.String rt(java.lang.String);
    Code:
    0: aload_1
    1: areturn
    public static void main(java.lang.String[]);
    Code:
    0: new #10; //class debug/Test
    3: dup
    4: ldc #11; //String
    6: invokespecial #12; //Method "":(Ljava/lang/String;)V
    9: pop
    10: return
    }

      明白了上面這些知識(shí),我們來(lái)做一個(gè)小測(cè)試吧:

    public class Test2 extends Test1
    {
    System.out.print("1");
    }
    Test2(){
    System.out.print("2");
    }
    static{
    System.out.print("3");
    }
    {
    System.out.print("4");
    }
    public static void main(String[] args) {
    new Test2();
    }
    }
    class Test1 {
    Test1(){
    System.out.print("5");
    }
    static{
    System.out.print("6");
    }
    }

      試試看能清楚打印的順序嗎?如果沒(méi)有new Test2()將打印什么?
    posted on 2008-07-23 17:21 胖胖泡泡 閱讀(131) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 免费人成在线观看视频高潮| 曰批全过程免费视频网址| 久久精品亚洲乱码伦伦中文| 好男人资源在线WWW免费| 亚洲婷婷综合色高清在线| 免费真实播放国产乱子伦| 久久国产乱子伦精品免费强| 中文有码亚洲制服av片| 不卡一卡二卡三亚洲| 四虎成年永久免费网站 | 羞羞视频免费网站日本| 亚洲国产精品久久| 国产精品色午夜视频免费看| a在线免费观看视频| 日韩国产欧美亚洲v片| 久久亚洲国产成人亚| 国产精品久久香蕉免费播放 | 日本免费人成视频播放| baoyu777永久免费视频| 亚洲欧美综合精品成人导航| 好看的亚洲黄色经典| 国产无遮挡吃胸膜奶免费看| 99热在线观看免费| 一个人看www免费高清字幕| 亚洲va精品中文字幕| 亚洲VA成无码人在线观看天堂 | 蜜臀91精品国产免费观看| 免费av一区二区三区| 污视频网站免费观看| 国产成人亚洲精品| 亚洲日本精品一区二区| 精品亚洲成α人无码成α在线观看 | 亚洲欧美aⅴ在线资源| 亚洲AV无码久久精品色欲| 免费人成在线观看网站视频| 毛片免费全部播放无码| 国产综合免费精品久久久| 亚洲AV无码一区二区三区电影 | 一个人看的免费观看日本视频www| 亚洲乱码一二三四区乱码| 亚洲区小说区图片区QVOD|