什麼時候會發生類初始化
前言
類的主動引用
如果在main()方法中去new一個子類的對象(子類繼承了父類),那麼JVM會自動初始化父類
由於這裏是new子類(Son類),父類沒有被初始化,所以JVM會自動初始化父類先
練習代碼1(主動引用(new 的形式))
// 測試類什麼時候會初始化
public class Test05 {
static {
System.out.println("Main類被加載");
}
public static void main(String[] args) throws ClassNotFoundException {
// 1、主動引用
// 由於這裏是new子類(Son類),父類沒有被初始化,所以JVM會自動初始化父類先
Son son = new Son();
}
}
class Father{
static int b = 2;
// 靜態代碼塊
static {
System.out.println("父類被加載");
}
}
class Son extends Father{
static {
System.out.println("子類被加載");
m = 300;
}
static int m = 100;
static final int M = 1;
}
運行結果:
Main類被加載
父類被加載
子類被加載
練習代碼2(主動引用(反射的形式))
// 測試類什麼時候會初始化
public class Test05 {
static {
System.out.println("Main類被加載");
}
public static void main(String[] args) throws ClassNotFoundException {
// 1、主動引用
// 由於這裏是new子類(Son類),父類沒有被初始化,所以JVM會自動初始化父類先
// Son son = new Son();
// 反射也會產生主動引用
Class.forName("com.lwm.reflection.Son");
}
}
class Father{
static int b = 2;
// 靜態代碼塊
static {
System.out.println("父類被加載");
}
}
class Son extends Father{
static {
System.out.println("子類被加載");
m = 300;
}
static int m = 100;
static final int M = 1;
}
結果與上面的一致
通過反射也是會產生類的主動引用,它會把所有東西加載進來(Main類被加載、父類被加載、子類被加載),這樣會極大的消耗資源
類的被動引用
通過子類去調用父類的靜態方法或者靜態變量,不會對子類產生任何影響,子類不會被加載
練習代碼1(被動引用(通過子類去調用父類的靜態方法或者靜態變量))
// 測試類什麼時候會初始化
public class Test05 {
static {
System.out.println("Main類被加載");
}
public static void main(String[] args) throws ClassNotFoundException {
// 不會產生類的引用的方法
// 通過子類去調用父類的靜態方法或者靜態變量,不會對子類產生任何影響,子類不會被加載
System.out.println(Son.b);
}
}
class Father{
static int b = 2;
// 靜態代碼塊
static {
System.out.println("父類被加載");
}
}
class Son extends Father{
static {
System.out.println("子類被加載");
m = 300;
}
static int m = 100;
static final int M = 1;
}
運行結果:
Main類被加載
父類被加載
2
練習代碼2(被動引用(通過數組形式))
數組佔了一個空間,開闢了5個空間(如果沒被加載說明什麼都沒幹(此時只有main類被加載))
// 測試類什麼時候會初始化
public class Test05 {
static {
System.out.println("Main類被加載");
}
public static void main(String[] args) throws ClassNotFoundException {
// 不會產生類的引用的方法
// 通過一個數組
// 數組佔了一個空間,開闢了5個空間(如果沒被加載說明什麼都沒幹(此時只有main類被加載))
Son[] array = new Son[5];
}
}
class Father{
static int b = 2;
// 靜態代碼塊
static {
System.out.println("父類被加載");
}
}
class Son extends Father{
static {
System.out.println("子類被加載");
m = 300;
}
static int m = 100;
static final int M = 1;
}
運行結果:
Main類被加載
爲什麼會加載Main類呢?
因爲當虛擬機啓動,就會先初始化main方法所在的類,然後才執行 Son[] array = new Son[5];這行代碼,這時沒有任何類被加載,這行代碼只是一個數組,它只是一個名字和一片空間而已
練習代碼3(被動引用(通過調用常量形式))
// 測試類什麼時候會初始化
public class Test05 {
static {
System.out.println("Main類被加載");
}
public static void main(String[] args) throws ClassNotFoundException {
// 不會產生類的引用的方法
// 調用子類的常量(常量並不會引起父類和子類的初始化)
System.out.println(Son.M);
}
}
class Father{
static int b = 2;
// 靜態代碼塊
static {
System.out.println("父類被加載");
}
}
class Son extends Father{
static {
System.out.println("子類被加載");
m = 300;
}
static int m = 100;
static final int M = 1;
}
運行結果:
Main類被加載
1
所有的常量和類的靜態變量都是在鏈接階段就被賦了一個值,在鏈接階段就做了,初始化的時候就已經存在了