Java - 物件的初始化
-
Java中的初始化
-
java會盡力保證所有的變數在使用前都能夠得到恰當的初始化,避免出現一堆null導致報錯
-
因此當變數是 基本型別 時,Java都會給他初始化一個初值
-
但如果變數是 物件型別 時,因為Java無法知道這個自定義的型別要給什麼初始化的值,因此如果沒有初始化的話,還是會得到一個null值
-
初始化的順序 : 先執行宣告變數時的初始化 -> 再執行構造器方法
class Leaf { int level; } class MyTest { //可以在此處宣告成員變數時,就給一個初始值 //或是也可以寫在構造器裡,兩種辦法都可以 int i = 100; int x; //也可以在宣告時,直接初始化物件型別 Leaf leaf = new Leaf(); Leaf leaf2; MyTest(){ i = 10; //輸出 10,此i被初始化了兩次,第一次被設為100,第二次被設為10 System.out.println(i); //輸出 0,此x則是因為被Java初始化了一次,所以值才會是0 System.out.println(x); //輸出
-
-
靜態資料的初始化
-
靜態資料
static
和類裡平常的成員變數一樣,也是java會進行基本的初始化(基本型別給值,物件型別給null),然而因為無論建立多少物件,靜態變數都只佔用一份儲存資料,所以如果想在宣告靜態變數之外進行初始化,需要使用靜態塊來初始化-
靜態塊只有在必要時刻才會進行,並不是程式啟動就會執行,只有在此類第一個物件被建立、或者第一次訪問靜態變數時,靜態塊才會被執行,所有的靜態變數就會被初始化,此後,所有靜態物件不會再次被初始化,因為所有此類的物件中,只會有一份靜態變數,而他們也只能初始化一次
-
由下面的例子可以看到,當靜態變數
i
i
、j
都會被初始化,因此當後面又在new
一個物件時,靜態塊並不會再次被初始化,因為整份類的所有物件中,靜態變數只有一份 -
使用
static {}
會建立一個靜態塊,而使用{}
則是建立普通塊,這兩個方法塊差別很大,很坑,要特別注意
class MyTest { static int i = 10; static int j = 20; //定義一個靜態塊,靜態變數的初始化放在這裡,或是在宣告變數時初始化 static { System.out.println("靜態塊初始化"); i = 100; } //要注意,這種前面沒有加 static 關鍵字的區塊,不是靜態塊 //是每建立一次物件都會執行的普通塊,並且會在構造器前執行,很坑 { System.out.println("普通塊初始化"); } MyTest() { System.out.println("constructor"); } } public class Main { public static void main(String[] args) { System.out.println("呼叫靜態變數 i"); System.out.println(MyTest.i); System.out.println("new物件開始"); MyTest myTest = new MyTest(); MyTest myTest2 = new MyTest(); System.out.println("new物件結束"); System.out.println("呼叫靜態變數 j"); System.out.println(MyTest.j); } }
呼叫靜態變數 i 靜態塊執行 100 new物件開始 普通塊初始化 constructor 普通塊初始化 constructor new物件結束 呼叫靜態變數 j 20
-
-
-
初始化的順序
-
建立一個物件時,初始化的順序
-
靜態變數宣告時初始化 -> 靜態塊初始化 -> 普通的變數宣告時初始化 -> 普通塊初始化 -> 構造器初始化
-
-
訪問一個靜態變數時,初始化的順序
-
靜態變數宣告時初始化 -> 靜態塊初始化
-
-
-
-
有繼承關係時的初始化
-
把握一個重點,就是靜態塊永遠優先於普通塊+構造器,然後才是Parent優先於Child
-
建立一個Child物件時,初始化的順序
-
Parent靜態塊 -> Child靜態塊 -> Parent普通塊 + Parent構造器 -> Child普通塊 + Child構造器
-
-
訪問一個靜態變數時,初始化的順序
-
如果是訪問Parnet的靜態變數,那就是隻初始化 Parent的靜態塊
-
但如果訪問了Child自己宣告的靜態變數,則會初始化 Parent靜態塊 + Child靜態塊
-
class Parent { public static int x = 10; static { System.out.println("parent 靜態塊"); } { System.out.println("parent 普通塊"); } Parent() { System.out.println("parent constructor"); } } class Child extends Parent { public static int y = 20; static { System.out.println("child 靜態塊"); } { System.out.println("child 普通塊"); } Child() { super(); System.out.println("child constructor"); } } public class Main { public static void main1(String[] args) { //main1 直接new一個Child物件 Child child = new Child(); } public static void main2(String[] args) { //main2 呼叫Parent的靜態變數 System.out.println("parent x: " + Child.x); } public static void main3(String[] args) { //main3 呼叫Child的靜態變數 System.out.println("child y: " + Child.y); } }
//main1結果 直接new一個Child物件 parent 靜態塊 child 靜態塊 parent 普通塊 parent constructor child 普通塊 child constructor //main2結果 呼叫Parent的靜態變數 parent 靜態塊 parent x: 10 //main3結果 呼叫Child的靜態變數 parent 靜態塊 child 靜態塊 child y: 20
-
-