我們的類初始化在類被載入時就會執行,這裡類被載入並不一定要實例化類的對象,只要用到這個類的方法或者屬性,就會對類進行初始化。 當類初始化時被載入到記憶體中的方法區中,並次創建成一個class類然後分配記憶體,類中的靜態屬性的顯式賦值語句和靜態代碼塊被放在一個叫<clinit>的方法中執行(按屬性和靜態代 ...
我們的類初始化在類被載入時就會執行,這裡類被載入並不一定要實例化類的對象,只要用到這個類的方法或者屬性,就會對類進行初始化。
當類初始化時被載入到記憶體中的方法區中,並次創建成一個class類然後分配記憶體,類中的靜態屬性的顯式賦值語句和靜態代碼塊被放在一個叫<clinit>的方法中執行(按屬性和靜態代碼塊在代碼中書寫的順序載入),這裡要註意,對於每一
個類,<clinit>方法只在類第一次被調用時執行一次,當第二次調用這個類的方法或者屬性時,就不會再被執行。
當被使用的類是某個類的子類時,這時首先初始化父類,然後再初始化子類,同樣的,父類也只被能被初始化一次,之後使用不會再被初始化,對於一個類,<clinit>方法只執行一次
而實例初始化是在實例化類的對象時進行的,也就是說,只要實例化一個對象,就會進行一次實例初始化。
實例初始化過程和類初始化過程相似,但都是非靜態的,非靜態屬性的顯式賦值和構造代碼塊還有構造器(註意註意:構造器是最後被初始化,其他的屬性和代碼塊按代碼書寫的順序載入)一起被放在一個叫<init>的方法中執行,每創建一
個對象就初始化一次,這一點和類初始化不同。
下麵提供幾個例題幫助理解:
第一題比較綜合,可從第二題開始
1 public class Test1 { 2 public static void main(String[] args) { 3 Zi zi = new Zi();//1 首先進入主方法,看到類被實例化,先進行類的初始化,然後進行實例初始化 4 } 5 } 6 class Fu{ 7 private static int i = getNum("(1)i");//3 首先進行靜態屬性的載入, 執行getNum方法 8 private int j = getNum("(2)j");//11 實例初始化父類,載入非靜態屬性 9 static{ 10 print("(3)父類靜態代碼塊");//6 載入靜態代碼塊並列印 (3)父類靜態代碼塊->1,父類實例化完畢 11 } 12 { 13 print("(4)父類非靜態代碼塊,又稱為構造代碼塊");//14 載入構造代碼塊 列印(4)父類非靜態代碼塊,又稱為構造代碼塊->2 14 } 15 Fu(){ 16 print("(5)父類構造器");//15最後調用構造器,列印 (5)父類構造器->2 父類實例初始化完成 ,進入子類 17 } 18 public static void print(String str){//5 列印(1)i->0 //13 (2)j->1 19 System.out.println(str + "->" + i); 20 } 21 public static int getNum(String str){//4 //12 22 print(str); 23 return ++i; 24 } 25 } 26 class Zi extends Fu{//2 找到對象所在類發現存在繼承關係,所以轉到父類先進行父類的初始化 27 private static int k = getNum("(6)k");//7 進入子類實例化,方法同 28 private int h = getNum("(7)h");//16同父類 29 static{ 30 print("(8)子類靜態代碼塊");//10 (8)子類靜態代碼塊->1 子類初始化完畢,開始進行實例初始化 31 } 32 { 33 print("(9)子類非靜態代碼塊,又稱為構造代碼塊");//19 (9)子類非靜態代碼塊,又稱為構造代碼塊->2 34 } 35 Zi(){ 36 print("(10)子類構造器");//20 (10)子類構造器->2 37 } 38 public static void print(String str){//9 (6)k->0 //18 (7)h->1 39 System.out.println(str + "->" + k); 40 } 41 public static int getNum(String str){//8 //17 42 print(str); 43 return ++k; 44 } 45 }
執行結果:
(1)i->0 (3)父類靜態代碼塊->1 (6)k->0 (8)子類靜態代碼塊->1 (2)j->1 (4)父類非靜態代碼塊,又稱為構造代碼塊->2 (5)父類構造器->2 (7)h->1 (9)子類非靜態代碼塊,又稱為構造代碼塊->2 (10)子類構造器->2
1 public class Test07 { 2 public static void main(String[] args) { 3 Son son = new Son(); 4 } 5 } 6 class Father{ 7 static{ 8 System.out.println("(1)父類的靜態代碼塊"); 9 } 10 { 11 System.out.println("(2)父類的非靜態代碼塊"); 12 } 13 Father(){ 14 System.out.println("(3)父類的無參構造"); 15 } 16 } 17 class Son extends Father{ 18 static{ 19 System.out.println("(4)子類的靜態代碼塊"); 20 } 21 { 22 System.out.println("(5)子類的非靜態代碼塊"); 23 } 24 Son(){ 25 System.out.println("(6)子類的無參構造"); 26 } 27 }
執行結果:
(1)父類的靜態代碼塊 (4)子類的靜態代碼塊 (2)父類的非靜態代碼塊 (3)父類的無參構造 (5)子類的非靜態代碼塊 (6)子類的無參構造
1 public static void main(String[] args) { 2 Sub s = new Sub(); 3 } 4 } 5 class Base{ 6 Base(){ 7 method(100); 8 } 9 { 10 System.out.println("base"); 11 } 12 public void method(int i){ 13 System.out.println("base : " + i); 14 } 15 } 16 class Sub extends Base{ 17 Sub(){ 18 super(); 19 super.method(70); 20 } 21 { 22 System.out.println("sub"); 23 } 24 public void method(int j){ 25 System.out.println("sub : " + j); 26 }
執行結果:
base sub : 100 sub base : 70
這題要註意,執行父類構造時發現一個method方法,這時要看實例化的對象是什麼,是子類就要看子類中有沒有同名方法,不能盲目調用父類的方法