java 类的加载、连接和初始化
JVM和類
調用Java命令運行Java程序時,該命令將會啟動一條Java虛擬機進程,不管該Java程序啟動了多少條線程,創建了多少個變量,它們都處于該Java虛擬機進程里,共享該JVM進程的內存區。當系統出現以下幾種情況時,JVM進程將被終止:
- 程序運行到最后正常結束;
- 程序運行到使用System.exit()或Runtime.getRuntime.exit()代碼結束程序;
- 程序運行過程中遇到未捕獲的異常或錯誤而結束;
- 程序所在的平臺強制結束了JVM進程。
類的加載
當程序主動使用某個類時,如果該類還沒有被加載到內存中,系統會通過加載、連接、初始化這三個步驟來對該類進行初始化(如果沒有意外,JVM將會連續完成這三個步驟,所以有時也會把這三個步驟統稱為類的加載或初始化)。
類的加載是指將類的class文件讀入內存,并為之創建一個java.lang.Class對象(注意并不是目標類的對象)。也就是說當程序中使用任何類時都會為之創建一個java.lang.Class對象。
類的加載由類加載器完成,類加載器通常由JVM提供,這些類加載器也是Java程序運行的基礎,JVM提供的這些類加載器通常被稱為系統類加載器。除此之外,開發者可以通過繼承ClassLoader基類來創建自己的類加載器。
通過使用不同的類加載器,可以從不同來源加載類的二進制數據,通常有如下幾種數據來源:
- 從本地文件系統加載class文件;
- 從jar包中加載class文件;
- 通過網絡加載class文件;
- 把一個Java源文件執行動態編譯,并執行加載。
java通常無需等到“首次使用”該類時才加載該類,Java虛擬機允許系統預先加載某些類。
類的連接
當類被加載后,系統會為之生成一個對應的Class對象,接著就會進入類的連接階段。
類的連接階段負責把類的二進制數據合并到JRE中。類的連接又可以分為如下三個階段:
- 驗證:驗證階段用于檢驗被加載的類是否有正確的內部結構,并和其他類協調一致;
- 準備:類的準備階段則負責為類的靜態屬性分配內存,并設置默認初始值;
- 解析:將類的二進制數據中的符號引用替換成直接引用。(關于符號引用和直接引用我覺得這里說的非常明白)
類的初始化
在類的初始化階段,虛擬機負責對類進行初始化,主要是對靜態屬性進行初始化。在java類中對靜態屬性進行初始化有兩種方式:
- 聲明靜態屬性時指定初始值;
- 使用靜態初始化塊為靜態屬性指定初始值。
進行初始化時,JVM會按語句在程序中的排列順序依次執行初始化。如下面的代碼,最終b的值為9。
package com.zhyea.test;public class Test {static{b=6;}static int a = 0;static int b = 9;}JVM對類進行初始化時包含如下步驟:
- 假如這個類還沒有被加載和連接,程序先執行加載并連接這個類;
- 假如該類的直接父類還沒有被初始化,則先初始化其直接父類;
- 假如類中有初始化語句,則系統依次執行這些初始化語句。
根據如上步驟可以看出來,當程序主動使用任何一個類時,系統會保證該類以及所有父類都會被初始化。
類初始化的時間
系統開始初始化類或接口的時間包括一下6種情況:
- 創建類的實例;
- 調用某個類的靜態方法;
- 訪問某個類或接口的靜態屬性,或為該靜態屬性賦值;
- 通過反射方式來創建某個類或接口對應的java.lang.Class對象,如使用Class.forName(“Person”);
- 初始化某個類的子類。初始化子類時,所有的父類都會被初始化;
- 直接使用java命令來運行某個類時。
需要一提的是final修飾的靜態屬性,如final修飾的靜態屬性在編譯時就得到了屬性值,那么該靜態屬性就會被當作常量不會被初始化(類的編譯做了哪些事情呢,這里需要考慮下)。如下面這種情況:
final static int MON = 1;final修飾的靜態屬性未能在編譯時得到屬性值,那么就會被初始化,如下面這種情況:
final static int TUE = 1+1;還值得一提的就是ClassLoader的loadClass方法并不會執行類的初始化,而是只執行了類的加載。
轉載于:https://www.cnblogs.com/amunote/p/4170627.html
總結
以上是生活随笔為你收集整理的java 类的加载、连接和初始化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《飞机大战》安卓游戏开发源码(三)
- 下一篇: exec和sp_executesql