Java向前引用容易出錯的地方

來源:互聯網
上載者:User

所謂向前引用,就是在定義類、介面、方法、變數之前使用它們,例如,

class MyClass  {      void method()      {          System.out.println(myvar);      }      String myvar = "var value";  }  

       myvar在method方法後定義,但method方法可以先使用該變數。在很多語言,如C++,是需要提前定義的,而Java已經允許了向前引用。不過在使用向前引用時可能會容易犯一些錯誤。例如,下面的代碼。

    class MyClass {           int method() {return n; }           int m = method();           int n = 1;      }  

如果簡單地執行下面的代碼,毫無疑問會輸出1.

System.out.println(new MyClass().method()); 

不過使用下面的代碼輸出變數m,卻得到0。

System.out.println(new MyClass().m);  

那麼這是真麼回事呢?

    實際上,從java編譯器和runtime的工作原理可以得知。在編譯java原始碼時只是進行了詞法、文法和語義檢測,如果都通過,會產生.class 檔案。不過這時MyClass中的變數並沒有被初始化,編譯器只是將相應的初始設定式(method()、1)記錄在.class檔案中。

    當runtime運行MyClass.class時,首先會進行裝載成員欄位,而且這種裝載是按順序執行的。並不會因為java支援向前引用,就首先初始 化所有可以初始化的值。首先,runtime會先初始化m欄位,這時當然會調用method方法,在method方法中利用向前引用技術使用了n。不過這 時的n還沒有進行初始化呢。runtime為了實現向前引用,在進行初始化所有欄位之前,還需要將所有的欄位添加到符號表中。以便在任何地方(但需要滿足 java的調用規則)都可以引用這些欄位,不過由於還沒有初始化這些欄位,所以這時符號表中所有的欄位都使用預設的值。int類型的欄位預設值自然是0 了。所以在初始化int m = method()時,method方法訪問的n實際上是在進行正式初始化之前已經被添加到符號表中的欄位n,而不是後面的int n = 1執行的結果。但將MyClass改成如下的形式,結果就完全不同了。

    class MyClass {          int method() {return n; }          int n = 1;          int m = method();      }  

現在執行下面的代碼,會輸出1.

    System.out.println(new MyClass().m);  

     究其原因,是引用初始化m時調用method方法,該方法中使用的n已經是初始化完的了,而不是最初放到符號表中的值。

    綜合上述,runtime在運行.class檔案時,每個範圍(方法、介面、類等帶語言元素都有自己的範圍)的符號表都會被至少訪問兩次,第一次會將 所有的欄位(這裡只考慮類的初始化)放到符號表中,暫時不考慮初始化只,放到符號表中只是相當於一個索引,好讓其他地方引用該欄位時可以找到它們,例 如,method方法中引用n時就會到符號表中尋找n,不過這時的n只是int類型的預設值。等到第二次訪問n就是真正初始化n的時候(int n = 1)。這是將符號表中儲存的欄位n的值更新為實際的初始化值(1)。所以如果引用n放生在正式初始化n之前,當然輸出的是0。

    那麼可能有人會問,先訪問一下n,再訪問m,這時m的值是否為1呢?答案仍然是0。因為在建立MyClass對象時m和n的初始化工作已經完成,它們的值已成事實,除非再次設定,否則不可改變了。

    MyClass myClass = new MyClass();      System.out.println(myClass.n);  //  輸出1      System.out.println(myClass.m);  //  仍然輸出0  

     對於靜態成員,仍然符合這一規則。  

    class MyClass {           static int method() {return n; }           static int m = method();  //  直接存取m,仍然會輸出0           static int n = 1;      }  
  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.