查看字节码指令的时候,可以看到每个new指令之后都会跟一个dup指令。
因为new指令之后,紧跟着就会调用指令invokespecial进行初始化,下面是invokespecial的指令格式。看一下操作数栈,需要一个objectref引用(对象的地址),后面是可选的参数;由于初始化没有返回值,调用之后没有东西入栈(用...表示没有入栈)。
也就是说初始化指令会使当前对象的引用出栈,如果不复制一份,操作数栈中就没有当前对象的引用了,后面再进行其他的关于这个对象的指令操作时,就无法完成。
例如public static void main(String[] args) {
String t = "aaa";
String t1 = t + "bbb";
}
指令0 ldc #2
2 astore_1
3 new #3
6 dup
7 invokespecial #4 ()V>
10 aload_1
11 invokevirtual #5
14 ldc #6
16 invokevirtual #5
19 invokevirtual #7
22 astore_2
23 return
3行 栈顶出现StringBuilder的引用
6行 复制一份,栈顶部有两份一样的引用
7行 栈顶引用出栈
11行 新的栈顶引用出栈完成invokevirtual调用,完成调用后返回对象的引用入栈,这时栈顶还是那个对象的引用。因为这个函数调用有返回值,而且是this。