【Java】深入理解i++、++i
先看两个例子
示例一
public class Test {
public static void main(String[] args) {
int i = 0;
int j = i++;
System.out.println("i=" + i);
System.out.println("j=" + j);
}
}
示例二?
public class Test {
public static void main(String[] args) {
int i = 0;
i = i++;
int j = i++;
System.out.println("i=" + i);
System.out.println("j=" + j);
}
}
结果都是
i=1
j=0
怎么解释?我猜你会说:“i先赋值给j,再自增”
额。。。可以这么理解,但代码在实际执行过程中不是这样的。因为在运算符优先级中,++优先于=,所以++会先运行,赋值后运行。
知识储备
这里简单说明,详细解释可网上查阅
1、运算符优先级:++优先于=,所以++会先运行,赋值后运行。
2、Java虚拟机的栈帧
????????局部变量表:用于存放临时变量,++是在这里面操作的
????????操作数栈:先进后出,用于数据操作,如加、减、乘与除的计算等等
????????动态链接:本文用不到,无视
????????方法返回地址:本文用不到,无视
3、Java虚拟机字节码指令
iconst_<i>:将数据<i>压入【操作数栈】,这里的i是数值
注:
iconst_<i>:i的取值范围是[-1,5]
bipush:[-128,127]
sipush:[-32768,32767]
ldc :[-2147483648,2147483647]
istore_<i>:将【操作数栈】栈顶的数据弹出(弹出后,栈里没有了),并存到【局部变量表】的<i>位置
注:静态变量i从0开始,非静态从1开始,所以后面代码里看到的是1开始的
iload_<i>:将【局部变量表】的<i>位置的数据,加载压入到【操作数栈】
iinc ? ? ? ? ?<i>,?<j>:将【局部变量表】的<i>位置的数据,加上<j>?
注:iinc时,【操作数栈】没有变化
下面进入正题
先用jdk自带的工具把【示例一代码】反编译成字节码,【示例二】原理相同,就不说明了。
获取class文件
javac Test.java
反汇编,得到字节码
javap -c Test.class
得到字节码代码?
public class com.test.Test {
public com.test.Test();
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
1: istore_1
2: iload_1
3: iinc 1, 1
6: istore_2
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: new #3 // class java/lang/StringBuilder
13: dup
14: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
17: ldc #5 // String i=
19: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: iload_1
23: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
26: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
32: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
35: new #3 // class java/lang/StringBuilder
38: dup
39: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
42: ldc #10 // String j=
44: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
47: iload_2
48: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
51: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
54: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
57: return
}
解读前5行
0: iconst_0? ? ? ? ? ? ? ? 》》常量0入【操作数栈】
1: istore_1? ? ? ? ? ? ? ? ?》》将【操作数栈】栈顶的数据弹出,并存到【局部变量表】1的位置,此时i=0
2: iload_1? ? ? ? ? ? ? ? ? 》》将【局部变量表】1位置的数据,压入【操作数栈】,此时,栈顶数据是0
3: iinc ? ? ? ? ?1, 1? ? ? ? 》》将【局部变量表】1位置的数据,加1,此时i=1
6: istore_2? ? ? ? ? ? ? ? 》》将【操作数栈】栈顶的数据弹出,并存到【局部变量表】2的位置,此时j=0
再来个++i的示例
源码
public class Test {
public static void main(String[] args) {
int i = 0;
int j = ++i;
System.out.println("i=" + i);
System.out.println("j=" + j);
}
}
字节码
public class com.test.Test {
public com.test.Test();
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
1: istore_1
2: iinc 1, 1
5: iload_1
6: istore_2
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: new #3 // class java/lang/StringBuilder
13: dup
14: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
17: ldc #5 // String i=
19: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: iload_1
23: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
26: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
32: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
35: new #3 // class java/lang/StringBuilder
38: dup
39: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
42: ldc #10 // String j=
44: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
47: iload_2
48: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
51: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
54: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
57: return
}
解读
0: iconst_0? ? ? ? ? ? ? ? 》》常量0入【操作数栈】
1: istore_1? ? ? ? ? ? ? ? 》》将【操作数栈】栈顶的数据弹出,并存到【局部变量表】1的位置,此时i=0
2: iinc ? ? ? ? ?1, 1? ? ? ? 》》将【局部变量表】1位置的数据,加1,此时i=1
5: iload_1? ? ? ? ? ? ? ? 》》将【局部变量表】1位置的数据,压入【操作数栈】,此时,栈顶数据是1
6: istore_2? ? ? ? ? ? ? ? 》》将【操作数栈】栈顶的数据弹出,并存到【局部变量表】2的位置,此时j=1
?运行结果
i=1
j=1
?希望对你有所帮助!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!