類中可以存在的成員:
class A{ 靜態成員變量; 非靜態成員變量; 靜態函數; 非靜態函數; 構造函數 A(..){...} 靜態代碼塊 static{...} 構造代碼塊 {...} }
類加載過程:
1、JVM會先去方法區中找有沒有類對應的.class存在,如果有,就直接使用;如果沒有,就把對應類的.class加載到方法區;
2、將.class加載到方法區的時候,分為兩部分,首先將非靜態內容加載到方法區的非靜態區域內;
3、再將靜態內容加載到方法區的靜態區域內,加載完成后,對所有的靜態成員變量進行默認初始化;
4、所有靜態成員變量默認初始化后,進行顯示賦值;再執行靜態代碼塊;(執行靜態代碼塊和靜態成員變量顯示賦值無先后順序,與代碼順序有關,誰在前面先執行誰)
5、如果有繼承關系,加載子類的時候會先加載父類,在加載子類。
對象創建過程:
1、對象創建首先會在堆內存中開辟一塊空間,並分配一個地址;
2、將對象的所有非靜態成員加載到開辟的空間下,並為所有非靜態成員變量進行默認初始化;
3、調用構造函數進棧執行,在執行構造函數的時候,首先會執行構造函數中的隱式三步,再執行構造函數中的代碼;
隱式三步:
1、執行super語句,調用父類的構造函數;
2、對所有非靜態成員變量進行顯示賦值;
3、執行構造代碼塊;(非靜態成員變量顯示賦值和執行構造代碼塊無先后順序,由代碼順序決定,誰在前先執行誰);
4、執行完隱式三步后,再執行構造函數中的代碼,代碼執行完后彈棧;
5、將堆內存中開辟的空間地址賦值給一個引用對象,對象創建完成。
下面用一段代碼來驗證一下類加載和對象創建過程(轉載自某位大牛):
1 //父類 2 public class Insect { 3 private int i = printInit("Insect:i"); 4 protected int j; 5 6 protected static int x1 = printInit("static Insect.x1 initialized"); 7 static{ 8 System.out.println("Insect靜態代碼塊"); 9 x1=80; 10 } 11 Insect() { 12 System.out.println("基類構造函數階段: i = " + i + ", j = " + j); 13 j = 39; 14 System.out.println(x1); 15 } 16 17 static int printInit(String s) { 18 System.out.println(s); 19 return 47; 20 } 21 22 } 23 //子類 24 public class Beetle extends Insect{ 25 { 26 k=90; 27 } 28 private int k = printInit("Beetle.k initialized"); 29 30 31 protected static int x2 = printInit("static Beetle.x2 initialized"); 32 33 34 public Beetle() { 35 System.out.println(k); 36 } 37 38 39 public static void main(String[] args) { 40 Beetle b = new Beetle(); 41 } 42 43 }
運行結果: