類的初始化

2022-09-06 18:00:10 字數 2302 閱讀 7558

類的使用順序:

類的裝載 -> 鏈結(驗證 -> 準備 -> 解析) -> 初始化 -> 物件例項化

class t  implements cloneable

static

//構造方法是個例項化方法,在 t 被例項化時呼叫

public t(string str)

public static int print(string str)

public static void main(string args)

}

一、載入(loading)

按如下三步執行

1.通過類的全名產生對應類的二進位制資料流。(注意,如果沒找到對應類檔案,只有在類實際使用時才丟擲錯誤。)

2.分析並將這些二進位制資料流轉換為方法區(jvm 的架構:方法區、堆,棧,本地方法棧,pc 暫存器)特定的資料結構(這些資料結構是實現有關的,不同 jvm 有不同實現)。這裡處理了部分檢驗,比如類檔案的魔數的驗證,檢查檔案是否過長或者過短,確定是否有父類(除了 obecjt 類)。

3.建立對應類的 j**a.lang.class 例項(注意,有了對應的 class 例項,並不意味著這個類已經完成了載入鏈鏈結!)。

二、鏈結(linking)

1.驗證(verification)

鏈結的第三部解析會把類中成員方法、成員變數、類和介面的符號引用替換為直接引用,而在這之前,需要檢測被引用的型別正確性和接入屬性是否正確(就是 public ,private 的的問題),諸如檢查 final class 又沒有被繼承,檢查靜態變數的正確性等等。(注意到實際上有一部分驗證過程已經在載入的過程中執行了。)

2.準備(preparation)

對類的成員變數分配空間。雖然有初始值,但這個時候不會對他們進行初始化(因為這裡不會執行任何 j**a **)。具體如下:

所有原始型別的值都為 0。如 float: 0f, int: 0, boolean: 0(注意 boolean 底層實現大多使用 int),引用型別則為 null。值得注意的是,jvm 可能會在這個時期給一些有助於程式執行效率提高的資料結構分配空間。比如方發表(類似與 c++中的虛函式表,參見另一篇博文《j**a:方法的虛分派和方法表》)。

3.解析(resolution)

為類、介面、方法、成員變數的符號引用定位直接引用(如果符號引用先到常量池中尋找符號,再找先應的型別,無疑會耗費更多時間),完成記憶體結構的布局。

這一步是可選的。可以在符號引用第一次被使用時完成,即所謂的延遲解析(late resolution)。但對使用者而言,這一步永遠是延遲解析的,即使執行時會執行 early resolution,但程式不會顯示的在第一次判斷出錯誤時丟擲錯誤,而會在對應的類第一次主動使用的時候丟擲錯誤!

另外,這一步與之後的類初始化是不衝突的,並非一定要所有的解析結束以後才執行類的初始化。不同的 jvm 實現不同。詳情見另一篇博文《j**a 類載入的延遲初始化》。

三、初始化類(initialization)

開發 j**a 時,接觸最多的是物件的初始化。實際上類也是有初始化的。相比物件初始化(參見博文 j**a 類的例項化),類的初始化機制要簡單不少。

類的初始化也是延遲的,直到類第一次被主動使用(active use),jvm 才會初始化類。(參見博文《j**a 類載入的延遲初始化》)

類的初始化分兩步:

1.如果基類沒有被初始化,初始化基類。

2.有類建構函式,則執行類建構函式。

類建構函式是由 j**a 編譯器完成的。它把類成員變數的初始化和 static 區間的**提取出,放到乙個的方法中。這個方法不能被一般的方法訪問(注意,static final 成員變數不會在此執行初始化,它一般被編譯器生成 constant 值)。同時,2中是不會顯示的呼叫基類的,因為 1 中已經執行了基類的初始化。類的初始化還必須注意執行緒安全的問題。

總結乙個類的初始化準備工作如下:

1.載入:這個由類載入器完成,他去查詢位元組碼,並且建立乙個class物件

2.連線:驗證類中的位元組碼,為靜態域分配儲存空間,並且如果必須的話,將解析這個類建立的對其他類的引用

3.初始化:如果這個類有超類,則對其進行初始化,執行靜態初始化器和靜態初始化**塊

初始化被延遲到了對靜態方法(構造器是隱式的靜態方法)或

非靜態方法的首次引用才執行

由上面可以知道,介面不能被初始化,如果想定義常量,必須是在介面的位元組碼被裝載到虛擬機器的時候他的常量就得被訪問,所以他必須是static final的

為什麼介面不能定義成員變數,而只能定義 final static 變數。

綜上述,static final 更適合於介面。

static final叫編譯期常量,不需要初始化就能讀取。

類的初始化

類的初始化通產有3種型別 使用初始化列表,在建構函式體中賦值,以及使用預設建構函式。先說前兩種 初始化列表與在建構函式體中賦值的區別在 呢?主要有兩點 第一,有的成員不能使用函式體中的 初始化。這其實就是初始化與賦值的區別 比如比如const 成員,引用型別,以及沒有定義預設建構函式的類,它們都必須...

類的初始化

類的初始化通產有3種型別 使用初始化列表,在建構函式體中賦值,以及使用預設建構函式。先說前兩種 初始化列表與在建構函式體中賦值的區別在 呢?主要有兩點 第一,有的成員不能使用函式體中的 初始化。這其實就是初始化與賦值的區別 比如比如const 成員,引用型別,以及沒有定義預設建構函式的類,它們都必須...

類的初始化

package 類的初始化 父類的初始化 1 j method 5 2 父類的靜態 塊 1 父類的例項初始化 1 super 最前 2 i test 3 父類的非靜態 塊 4 父類的無參構造 最後 非靜態方法前面其實有乙個預設的物件this this在構造器 或 它表示的是正在建立的物件 因為這裡是...