本文實例為大家介紹了java虛擬機指令dup,供大家參考,具體內(nèi)容如下
舉個例子:
1
2
3
4
5
6
7
8
|
public class ExceptionTest{ void cantBeZero( int i) throws Exception{ throw new Exception(); } } |
上面代碼編譯后的字節(jié)碼指令如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
void cantBeZero( int ) throws java.lang.Exception; descriptor: (I)V flags: Code: stack= 2 , locals= 2 , args_size= 2 0 : iload_1 1 : ifne 12 4 : new # 2 // class java/lang/Exception 7 : dup 8 : invokespecial # 3 // Method java/lang/Exception."<init>":()V 11 : athrow 12 : return |
1) 其中new指令在java堆上為Exception對象分配內(nèi)存空間,并將地址壓入操作數(shù)棧頂;
2) 然后dup指令為復制操作數(shù)棧頂值,并將其壓入棧頂,也就是說此時操作數(shù)棧上有連續(xù)相同的兩個對象地址;
3) invokespecial指令調(diào)用實例初始化方法<init>:()V,注意這個方法是一個實例方法,所以需要從操作數(shù)棧頂彈出一個this引用,也就是說這一步會彈出一個之前入棧的對象地址;
4) athrow指令從操作數(shù)棧頂取出一個引用類型的值,并拋出;
5) 最后由return指令結(jié)束方法。
從上面的五個步驟中可以看出,需要從棧頂彈出兩個實例對象的引用,這就是為什么會在new指令下面有一個dup指令,其實對于每一個new指令來說一般編譯器都會在其下面生成
一個dup指令,這是因為實例的初始化方法肯定需要用到一次,然后第二個留給程序員使用,例如給變量賦值,拋出異常等,如果我們不用,那編譯器也會生成dup指令,在初始化方法調(diào)用完成后再從棧頂pop出來。例如我們僅僅創(chuàng)建一個對象而不做任何操作,例如:
1
2
3
4
|
void cantBeZero( int i) throws Exception{ new Exception(); } |
上面的代碼僅僅創(chuàng)建了一個Exception對象,而沒有做任何操作。
其編譯后的字節(jié)碼指令如下:
1
2
3
4
5
6
7
8
9
10
|
void cantBeZero( int ) throws java.lang.Exception; descriptor: (I)V flags: Code: stack= 2 , locals= 2 , args_size= 2 0 : new # 2 // class java/lang/Exception 3 : dup 4 : invokespecial # 3 // Method java/lang/Exception."<init>":()V 7 : pop 8 : return |
也會生成一個dup指令,只不過在調(diào)用完實例初始化方法后,將重復的實例引用又pop出棧了。不過這種情況基本不會出現(xiàn)在我們的代碼中,因為我們創(chuàng)建的每一個對象都應該是有用的。
通過上面的例子你應該比較清楚的理解了為什么創(chuàng)建對象時總會有一個dup指令了。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://www.cnblogs.com/CLAYJJ/archive/2017/10/20/7698035.html