dup:java
複製棧頂元素並壓入棧程序員
pop:this
出棧操做code
代碼對象
public class JvmTest1{ public static void testMethod(){ new JvmTest1(); } }
編譯字節碼文件內存
javap -c JvmTest1.class
Compiled from "JvmTest1.java" public class JvmTest1 { public JvmTest1(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void testMethod(); Code: 0: new #2 // class JvmTest1 3: dup 4: invokespecial #3 // Method "<init>":()V 7: pop 8: return }
1) 其中new指令在java堆上爲JvmTest1對象分配內存空間,並將地址壓入操做數棧頂;ci
2) 而後dup指令爲複製操做數棧頂值,並將其壓入棧頂,也就是說此時操做數棧上有連續相同的兩個對象地址;編譯器
3) invokespecial指令調用實例初始化方法<init>:()V,注意這個方法是一個實例方法,因此須要從操做數棧頂彈出一個this引用,也就是說這一步會彈出一個以前入棧的對象地址;it
4) 在調用完實例初始化方法後,將重複的實例引用又pop出棧了。由於我只new了一個JvmTest1對象,並無使用。不過這種狀況基本不會出如今咱們的代碼中,由於咱們建立的每個對象都應該是有用的。編譯
5) 最後由return指令結束方法。
從上面的五個步驟中能夠看出,須要從棧頂彈出兩個實例對象的引用,這就是爲何會在new指令下面有一個dup指令,其實對於每個new指令來講通常編譯器都會在其下面生成一個dup指令,這是由於實例的初始化方法確定須要用到一次,而後第二個留給程序員使用,例如給變量賦值,拋出異常等,若是咱們不用,那編譯器也會生成dup指令,在初始化方法調用完成後再從棧頂pop出來。