在看《深入理解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指令存储到局部变量表中。