被final修飾靜态字段在操作使用時,不會使類進行初始化,因為在編譯期已經将此常量放在常量池。
測試:
class ClassLoadTime{
static{
System.out.println("ClassLoadTime類初始化時就會被執行!");
}
public static final int MIN = 10; (防止測試類和此類不在一個包,使用public修飾符)
}
class ClassLoadDemo{
public static void main(String[] args){
System.out.println(ClassLoadTime.MIN);
}
}
由于編譯器編譯優化,導緻該變量在常量池中,當你用ClassLoadTime.MIN時,隻會到常量池中查該數值,不會加載ClassLoaderTime類。
輸出:
10
————————————————
版權聲明:本文為CSDN部落客「冰淩其」的原創文章,遵循 CC 4.0 BY-SA 版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/xiao1_1bing/article/details/81139926
在看到上述文章的這段内容時有一個疑問,如果我通路的屬性類型是一個引用類型的話也不會初始化 ClassLoaderTime類嗎?于是用一下代碼測試了一下:
public class HungrySingletonPattern {
static{
System.out.println("HungrySingletonPattern類初始化時就會被執行!");
}
public static final HungrySingletonPattern instance = new HungrySingletonPattern();
public static final String str = "調我不用初始化類!";
private HungrySingletonPattern() {
super();
// TODO Auto-generated constructor stub
}
public static final HungrySingletonPattern getInstance(){
return instance;
}
}
public class Test {
public static void main(String[] args) throws SecurityException, NoSuchFieldException {
HungrySingletonPattern i = HungrySingletonPattern.instance;
// String s = HungrySingletonPattern.str;
}
}
運作結果如下:
HungrySingletonPattern類初始化時就會被執行!
說明這個HungrySingletonPattern類被初始化了!為什麼上邊的例子不會初始化類,在把類中屬性換成引用類型時類就會被初始化呢?上邊的例子說是編譯器的優化導緻的,那麼我們就來看看兩段代碼生成的位元組碼有什麼差別吧:
1. main函數中調用HungrySingletonPattern.str的情況:
Code:
stack=1, locals=2, args_size=1
0: ldc #21 // String 調我不用初始化類!
2: astore_1
3: return
2. main函數中調用HungrySingletonPattern.instance的情況:
Code:
stack=1, locals=2, args_size=1
0: getstatic #21 // Field cn/edu/xidian/singleton/h
ungry/HungrySingletonPattern.instance:Lcn/edu/xidian/singleton/hungry/HungrySing
letonPattern;
3: astore_1
4: return
我們發現上述兩個例子中生成的位元組碼唯一的差別就是1中生成的指令是ldc指令,而2中生成的指令是getstatic指令。那麼這兩個指令都是什麼含義呢?
我們通過查詢java虛拟機規範發現指令的解釋如下:
0xb2 | getstatic | 擷取指定類的靜态域,并将其值壓入棧頂。 |
0x12 | ldc | 将 int,float 或 String 型常量值從常量池中推送至棧頂。 |
是以我們可以大膽的推測:當類中的基本類型或String類型在被static final修飾時,編譯器會将指令直接優化成ldc指令,進而在隻擷取該屬性的值時,不需要初始化它所在的類;而當被static final修飾的屬性為引用類型時,由于編譯器無法直接将其轉化為常量,故在擷取該類型的屬性時還是需要初始化類的。