版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_21586317/article/details/81710826
一、问题一:执行如下代码,将会输出什么?
1.代码:
public class A {
public static void main(String[] args) {
int i = 0;
i = i++;
System.out.println(i);
int k = 0;
k = ++k;
System.out.println(k);
}
}
2.执行结果:
二、问题二:为什么 ++ 的位置不同会输出不同的结果
Java 代码在执行前会被编译成一个 .class 字节码文件,随后 JVM 会把这份编译好的字节码文件翻译成平台的机器指令
1.生成 .class 文件
javac A.java
2.查看编译之后的 .class 字节码文件
javap -c A
如图所示
图中的指令涉及到了两个数据结构,一个是操作数栈(operand stack),另一个是局部变量表(local variable),前者是栈,后者是数组
和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组。但是和前者不同的是,它不是通过索引来访问,而是通过标准的栈操作—压栈和出栈—来访问的。比如,如果某个指令把一个值压入到操作数栈中,稍后另一个指令就可以弹出这个值来使用
.class 字节码文件内容如下:
public class A {
public A();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_0 // 0 入栈
1: istore_1 // 0 出栈给 index = 1 位置的变量 i 进行赋值,赋值为 0
2: iload_1 // 把 index = 1 位置的变量的值 0 压入栈中,栈顶为 0
3: iinc 1, 1 // 对 index = 1 位置的变量 i 的值加一,此时 index = 1 位置的变量 i 的值由 0 变成 1
6: istore_1 // 弹出栈顶的值 0,赋值给 index = 1 位置的变量 i,i 从 1 又变成了 0
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1 // 把 index = 1 位置的变量 i 的值 0 压入栈中,栈顶为 0
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iconst_0 // 0 入栈
15: istore_2 // 0 出栈给 index = 2 位置的变量 k 进行赋值,赋值为 0
16: iinc 2, 1 // 对 index = 2 位置的变量 k 的值加一,此时 index = 2 位置的变量 k 的值由 0 变成 1
19: iload_2 // 把 index = 2 位置的变量 k 的值 1 压入栈中,栈顶为 1
20: istore_2 // 弹出栈顶的值 1,赋值给 index = 2 位置的变量 k,即 k 的值由 1 变成 1
21: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
24: iload_2 // 把 index = 2 位置的变量的值 1 压入栈中,栈顶为 1
25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
28: return
}
结果:指令执行到 6: istore_1 位置后,i++ 的结果是 0,指令执行到 20: istore_2 时,++k 的结果是 1
i = i++
等价于
temp = i;
i = i + 1;
i = temp;
// The assignment to variable k has no effect
k = ++k
等价于
k = k = k + 1
所以编译器会警告对变量 k 的赋值没有作用