【JVM類加載】類的加載,連接與初始化
類加載
- 在java代碼中,類型的加載,連接與初始化過程都是在程序運行期間完成的(類class文件信息在編譯期間已經確定好)。
- 提供了更大的靈活性,增加了更多的可能性。
類加載器
java虛擬機與程序的生命周期:
在如下幾種情況下,java虛擬機將結束生命周期:
- 執行System.exit()方法
- 程序正常執行結束
- 程序在執行過程中遇到了異常或錯誤向上拋出異常拋到main入口程序終止
- 由于操作系統出現錯誤而導致java虛擬機進程終止
類的加載流程三部分
加載:查找并加載類的二進制數據
連接 :
驗證:確保被加載的類的正確性(字節碼是否符合JVM的規范)
準備:為類的靜態變量分配內存,并將其初始化值設置為默認值
如 public static int a = 1; 先設置為默認值0.
解析: 把類中的符號引用轉換成直接引用
初始化:為類的靜態變量賦予正確的初始值未開發人員定義的靜態變量賦予真實的值。
解析過程
類的使用與卸載
- 使用
- 卸載
類的加載,連接與初始化
java程序對類的使用方式可分為兩種:
- 主動使用
所有的java虛擬機實現必須在每個類或接口被java程序“首次主動使用”時才初始化他們。
- 被動使用
類的加載,連接,初始化。
初始化和實例化的區別?
初始化只是類加載,只執行一次,即只有有一個類對象(注意不是實例對象),無論你以后怎么個new法,新new的都是實例對象。
Object o = null; 或者 Objects o;// 這個叫初始化,只在棧內存中存在,并沒有獲取到實際的引用o = new Object(); // 這是實例化()。
spring bean的初始化(區別類的初始化實例化)。
spring bean的初始化,是對實例化出來的對象進行填充初始化。
實例化(Instantiation)—-實例化的過程是一個創建Bean的過程,即調用Bean的構造函數,單例的Bean放入單例池中。
初始化(Initialization)—-初始化的過程是一個賦值的過程,即調用類對象的setter,設置類對象的屬性 區別類加載 spring bean實例在前初始化在后。
主動使用(七種)
- 創建實例類
- 訪問某個類或接口的靜態變量,或者對該靜態變量賦值
- 調用類的靜態方法
- 反射
- 初始化一個類的子類
- java虛擬機啟啟動時被表明為啟動類的類
- JDK1.7開始提供的動態語言支持:java.lang.invoke.MethodHandle實例的解析結果REF_getStitac,REF_putStatic,REF_invokeStatic句柄對應的類沒有初始化則初始化
助記符:
助記符
- getstatic 初始化時訪問靜態變量。
- putstatic 初始化時給靜態方法賦值。
- invokestatic 初始化時調用靜態方法。
/**
* 1.System.out.println(MyParent1.str)對于靜態字段來說,只有定義了該字段的類才會被初始化
* 2.System.out.println(MyChild1.str2)對于子類被初始化,要求其父類全部被初始化完畢
*/
public class Test01 {
public static void main(String[] args) {
System.out.println(MyParent1.str); //調用父類的靜態變量時 子類沒有被初始化
// System.out.println(MyChild1.str2); //全部初始化
}
}
class MyParent1{
public static String str = "hello word";
static {
System.out.println("MyParent1 static block");
}
}
class MyChild1 extends MyParent1{
public static String str2 = "welecome";
static {
System.out.println("MyChild1 static block");
}
}
除了以上7種情況,其他使用java類的方式都被看做是對類的被動使用,都不會導致類的初始化。
類的加載
類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然后在內存中創建一個java.lang.Class對象(規范化并未說明Class對象位于哪里,HotSpot虛擬機將其放在方法區中)用來封裝類在方法區內的數據結構。
記載.class文件的方式
- 從本地系統中直接加載(自己編寫的)。
- 通過網絡載.class文件。
- 從zip.jar等歸檔文件中加載.class文件(maven)。
- 將源文件動態編譯為.class文件(動態代理,cglib)。
- 從專有的數據庫中提取.class文件。
//常量在編譯階段會存入到調用這個常量的方法所在的類的常量池中
//本質上,調用類并沒有直接引用到定義常量的類,因此并不會觸發 定義常量的類的初始化
// 注意:這里指的是將常量存放到了Test2的常量池中,之后Test2與MyParent2就沒有任何關系了
// 甚至,我們可以將MyParent2的class文件刪除
/**
* javap -c 查看助記符
* ldc標識將int,float或是String類型的常量值從常量池中推送到棧頂
* bipush標識將單字節(-128 - 127)的常量值推送至棧頂
* sipush表示將一個短整型常量值(-32768 - 32767)推送至棧頂
* iconst_1表示將int類型1推送至棧頂(iconst_1 ~ iconst_5)
* iconst_m1表示將int類型-1推送至棧頂
*/
public class Test2 {
public static void main(String[] args) {
System.out.println(MyParent2.i);
}
}
class MyParent2{
public static final String str = "hello world";
public static final int i = 128;
static {
System.out.println("Myparent2 static block");
}
}
/*
當一個常量的值并非編譯期間可以確定的,那么其值就不會被放到調用類的常量池當中,
這時在程序運行時,會導致主動使用這個常量所在的類,顯然會導致這個類被初始化。
*/
public class Test3 {
public static void main(String[] args) {
System.out.println(MyParent3.STRING);
}
}
class MyParent3{
public static final String STRING = UUID.randomUUID().toString();
static {
System.out.println("MyParent3 static code");
}
}
接口:
/*
當一個接口在初始化時,并不要求其父接口都完成了初始化
只有在真正使用到父接口的時候 (引用接口中定義的常量時),才會初始化
*/
public class Test5 {
public static void main(String[] args) {
System.out.println(MyChild5.b);
}
}
interface MyParcnt5{
public static final int a = 5;
}
interface MyChild5 extends MyParcnt5{
public static int b = new Random().nextInt(4);
}
public class Test6 {
public static void main(String[] args) {
Singleton singleton = Singleton.getSingleton();
System.out.println("i=" + Singleton.i);
System.out.println("b=" + Singleton.b);
}
}
//當類加載時 程序是自上而下執行的
// 靜態變量:類變量,類的所有實例都共享,我們只需知道,在方法區有個靜態區,靜態區專門存放靜態變量和靜態塊。
class Singleton {
public static int i;
public static Singleton singleton = new Singleton();//又初始化
private Singleton() {
i++;
b++;//準備階段的意義
//此時 i和b都被賦值為1
System.out.println(i);
System.out.println(b);
}
//此時 b= 1 又被賦值為0
public static int b = 0;
public static Singleton getSingleton() {
return singleton;
}
}
/*
1
1
i=1
b=0
*/
注意:一定要將初始化和實例化分開 初始化時將一個類里的靜態變量附上正確的值(程序員需要賦的值) 一個.clas類只初始化一次,實例化他可以多次創建沒new一次就是一個實例化 (初始化不一定實例化實例化一定初始化了)。
靜態變量初始化