咱們的類初始化在類被加載時就會執行,這裏類被加載並不必定要實例化類的對象,只要jvm在第一次用到這個類的方法或者屬性時發現內存中沒有加載過這個類,就會對類進行初始化。jvm
當類初始化時被加載到內存中的方法區中,並次建立成一個class對象存儲類的信息,而後分配內存執行,類中的靜態屬性的顯式賦值語句和靜態代碼塊被放在一個叫<clinit>的方法中執行(按屬性和靜態代碼塊在代碼中書寫的spa
順序加載),這裏要注意,對於每個類,<clinit>方法只在類第一次被調用時執行一次,當第二次調用這個類的方法或者屬性時,就不會再被執行。code
當被使用的類是某個類的子類時,這時首先初始化父類,而後再初始化子類,一樣的,父類也只被能被初始化一次,以後使用不會再被初始化,對於一個類,<clinit>方法只執行一次 對象
而實例初始化是在實例化類的對象時進行的,也就是說,只要實例化一個對象,就會進行一次實例初始化。 blog
實例初始化過程和類初始化過程類似,但都是非靜態的,非靜態屬性的顯式賦值和構造代碼塊還有構造器(注意注意:構造器是最後被初始化,其餘的屬性和代碼塊按代碼書寫的順序加載)一塊兒被放在一個叫<init>的方法中執行,每建立一繼承
個對象就初始化一次,這一點和類初始化不一樣。內存
下面提供幾個例題幫助理解:get
第一題比較綜合,可從第二題開始it
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 }
執行結果:class
(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方法,這時要看實例化的對象是什麼,是子類就要看子類中有沒有同名方法,不能盲目調用父類的方法