在看《深入理解Java虛擬機:JVM高級特性與最佳實踐(第二版)》這本書時,有幾處的字節碼在new之後會緊接着出現dup指令,我麼以書中253頁的字節碼爲例,說明dup指令的作用。
其中Java代碼爲:
public class DynamicDispatch {
static abstract class Human {
protected abstract void sayHello();
}
static class Man extends Human {
@Override
protected void sayHello() {
System.out.println("man say hello");
}
}
static class Woman extends Human {
@Override
protected void sayHello() {
System.out.println("woman say hello");
}
}
public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
man.sayHello();
woman.sayHello();
man = new Woman();
man.sayHello();
}
}
對應的字節碼爲:
public static void main(java.lang.String[]);
Code:
0: new #16 // class jvm/fenixsoft/DynamicDispath$Man
3: dup
4: invokespecial #18 // Method jvm/fenixsoft/DynamicDispach$Man."<init>":()V
7: astore_1
8: new #19 // class jvm/fenixsoft/DynamicDispath$Woman
11: dup
12: invokespecial #21 // Method jvm/fenixsoft/DynamicDispach$Woman."<init>":()V
15: astore_2
16: aload_1
17: invokevirtual #22 // Method jvm/fenixsoft/DynamicDispach$Human.sayHello:()V
20: aload_2
21: invokevirtual #22 // Method jvm/fenixsoft/DynamicDispach$Human.sayHello:()V
24: new #19 // class jvm/fenixsoft/DynamicDispath$Woman
27: dup
28: invokespecial #21 // Method jvm/fenixsoft/DynamicDispach$Woman."<init>":()V
31: astore_1
32: aload_1
33: invokevirtual #22 // Method jvm/fenixsoft/DynamicDispach$Human.sayHello:()V
36: return
關於dup指令的作用,在《深入理解Java虛擬機》這本書中是這麼描述的。這是一個操作數棧管理指令,負責複製棧頂(注意,這個棧指的是操作數棧)一個或者兩個數值並將複製值或雙份的複製值重新壓人棧頂。
簡單理解就是給操作數棧棧頂的元素弄了一個備份。
那麼爲什麼要進行備份呢?
一開始是new指令在堆上分配了內存並向操作數棧壓入了指向這段內存的引用,之後dup指令又備份了一份,那麼操作數棧頂就有兩個,再後是調用invokespecial #18指令進行初始化,此時會消耗一個引用作爲傳給構造器的“this”參數,那麼還剩下一個引用,會被astore_1指令存儲到局部變量表中。