1. 程式人生 > >Java程式執行和物件建立過程簡述

Java程式執行和物件建立過程簡述

Java中一個物件建立分為兩個步驟: 載入類,建立物件

載入類是將所寫的程式.java檔案編譯生成的.class檔案載入到記憶體中,保證了物件建立的預置環境。類載入完畢後才可以建立該類的物件。

第一步:載入類

1. 當開始執行一個類,虛擬機器首先試圖訪問指定啟動類的 .main() 方法,載入該類的 .class 檔案。

2. 如果該類有父類,那麼繼續載入其父類,以此類推,直到加載出所有與main入口類相關的類(它的父類,父類的父類等)。

3. 接著,從其頂級父類開始,對其static域按照順序進行初始化!直至初始化完所有類的static域。>將static域放到靜態儲存區。

4. 至此類的載入工作完畢了,下面就進入main函式,執行main函式

。一般main函式中來建立類的物件,如果發現要建立的類沒有被載入,則繼續載入該類)

第二步:物件建立

1. 為物件獲取記憶體,然後將記憶體全部置為0,此時物件中的所有屬性都是被賦予0的預設值(記憶體為0時候的預設值:null-物件引用,0-int,false-boolean...)> 在堆中生成物件所需空間,全部初始化為0,具體成員屬性值為堆上對應記憶體子塊--正是因為這種機制,所以java可以保證所有的類物件的屬性都會被初始化,但是區域性不會被初始化。

  這裡需要注意的是:一個物件內部組合了另一個物件,那麼在堆中其實存的也是一個引用,這個引用指向被組合物件的堆記憶體地址(另外再建立)。當引用在記憶體的二進位制資料都為0的時候,他的表現形式是null;當他指向的資料內容記憶體區資料都是0的時候,他的值為0,"",False等初始標準值。所謂初始化就是修改記憶體區的二進位制資料,因為物件在建立時候第一步就將記憶體清0,所以保證了所有屬性都能至少被初始化為標準初值!但是區域性變數不一樣,你不初始化,只是申明,那麼開闢的記憶體區在棧中值會是一個未知資料(一旦使用該引用的話,使用的可能是你沒有初始化而瞎幾把亂指的地址)所以Java會程式碼檢驗的時候發現你使用了未初始化的引用,直接給予不通過,直接杜絕了這種可能性的發生。綜上,Java中使用任何變數或引用,必須初始化,初始化就是將記憶體中舊的二進位制資料要麼清0,要麼賦予你要賦的值!

2. 從頂級父類開始,按照申明順序將給頂級父類的非static的成員屬性初始化(static的只初始化一次在類載入階段)> 用屬性定義的值覆蓋0值。

3. 呼叫頂級父類的建構函式,如果有成員屬性初始化則覆蓋前一個申明時初始化值。> 建構函式再次初始化,覆蓋前面申明時初始化。

4. 以此類推,將所有的父級(先初始化屬性,在呼叫構造,一層一層的構造完畢) 構造完成

5. 最後,初始化當前類的非static屬性,再呼叫當前類的建構函式,完成所有初始化工作。

注意:

1、類中static部分是發生在類載入時期的,並且只初始化一次。因為類只加載一次,載入完後建立物件過程中不會再去初始化static部分的東西,所以之後根本不會再走那塊初始化程式碼,又怎麼初始化第二次呢?

2、static的優先順序是高於main函式執行的,因為它是在類載入時期初始化。當static作用的東西都載入完了才執行main,當然main是第一個被使用的static方法,但是虛擬機器只是找到這個方法的位置,並不會先去執行裡面的內容。

2、對於類的普通成員屬性初始化三個步驟:先全初始化為0,再用申明時候初始化值進行初始化,再呼叫建構函式進行初始化。

例項程式:(來源於Thinking in Java)

//: reusing/Beetle.java
// The full process of initialization.
import static net.mindview.util.Print.*;
 
 
class Insect {
  private int i = 9;
  protected int j;
  Insect() {
    print("i = " + i + ", j = " + j);
    j = 39;
  }
  private static int x1 =
    printInit("static Insect.x1 initialized");
  static int printInit(String s) {
    print(s);
    return 47;
  }
}
 
 
public class Beetle extends Insect {
  private int k = printInit("Beetle.k initialized");
  public Beetle() {
    print("k = " + k);
    print("j = " + j);
  }
  private static int x2 =
    printInit("static Beetle.x2 initialized");
  public static void main(String[] args) {
    print("Beetle constructor");
    Beetle b = new Beetle();
  }
} 



   /* Output:
    static Insect.x1 initialized  
    static Beetle.x2 initialized //1.類載入和初始化靜態x1,x2:只會初始化一次!
    Beetle constructor //2.進入main函式
    i = 9, j = 0  
    //3.new Beetle(),先初始化父類>申請父類記憶體>初始化為0>初始化i=9,j=0>呼叫Insect()建構函式>輸出ij值>初始化j=39
    Beetle.k initialized //4.初始化子類>申請子類記憶體>..>初始化k,輸出改行>呼叫構造Beetle()>輸出下面的k,j
    k = 47
    j = 39
    *///:~