初始化順序的規則
1.在一個類的對象實例化時,成員變量首先初始化,然后才調用構造器,無論書寫順序。如果調用構造器前,沒有顯式初始化,那么會賦默認值。
這樣做法的原因可以理解為:構造器執行時可能會用到一些成員變量的初值。
2.static變量早于所有其他的類成員變量初始化,同樣無論書寫順序。但是static變量僅在所在類第一次被使用時初始化一次。
3.基類構造器總是在導出類的構造過程中被調用,而且按照繼承層級逐漸向上鏈接(調用順序則是從基類開始向下)。可以理解為,這么做的邏輯關系是在一個類構建時可能會用到其父類的成員、方法。在清理時順序相反。
4.成員的初始化方法(包括基本數據類型的賦值)在基類構造器調用之后才會被調用。最初時,分配給對象的存儲空間初始化二進制的零。
例一出自《Java編程思想》第5.7.2節,為了便于演示初始化順序,進行了縮減和重新編號。用構造器的參數標明執行順序,演示1~2條規則:
class Bowl { Bowl(int marker) { System.out.輸出及對應注釋:
Bowl(1) //第一個static變量Bowl(2) //第二個static變量Bowl(3) //第一個對象的第一個非static成員變量Bowl(4) //第一個對象的第一個非static成員變量i:0 //未顯示初始化的成員變量Bowl(5) //更改static變量的值Bowl(3) //第二個對象的第一個非static成員變量Bowl(4) //第二個對象的第二個非static成員變量i:0Bowl(6)
例二是一個演示第3條規則的簡單示例。
class A { A() { System.out.println("A"); }}class B extends A { B() { System.out.println("B"); }}class C extends B { C() { System.out.println("C"); }}public class hrt { public static void main(String args[]) { new C(); }}輸出
ABC
例三用于演示規則4。調用父類構造器時,構造器中的方法被子類方法覆蓋。
class Glyph { void draw() { System.out.println("Glyph.draw("); } Glyph() { System.out.println("Glyph() before draw()"); draw(); System.out.println("Glyph() after draw()"); }}class RoundGlyph extends Glyph { int radius = 1; RoundGlyph(int r) { radius = r; System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius); } void draw() { System.out.println("RoundGlyph.draw(), radius = " + radius); }}public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5); }}這么多條規則,記起來實在讓人頭大。將它們按順序編排會易讀很多。
對象初始化順序,如果有對應成員/父類的才執行對應條目:
1.將分配給對象的存儲空間初始化為二進制的零;
2.調用基類構造器,從最頂層/根的基類開始;
3.按照聲明的順序,使用直接的賦值或者初始化方法,先依次初始化static變量,再依次初始化非static變量;
4.調用本對象所屬類的構造器。
新聞熱點
疑難解答