最近网上看到一个面试题目是关于i++和++i,对于i++ 和++i 很多人都知道是不一样的,i=i++ 和 i=++i, 未必有人知道其中的奥妙,看了很多文章关于i++和++i的区别,都没有指出其中不一样的根本原因。有人说i++是线程安全的,有人说不是的,如果不是的那原因是什么呢?
我们先看下面一个例子
public class Test {
public static void main(String[] args) {
int i=0;
i=i++;
int j=0;
j=++j;
}
}
javap是jdk自带的一个工具,可以反编译,也可以查看java编译器生成的字节码, 通过查看字节码, 我们可以知道java代码在JVM中的运行过程
-l 输出行和变量的表
-public 只输出public方法和域
-protected 只输出public和protected类和成员
-package 只输出包,public和protected类和成员,这是默认的
-private 输出所有类和成员
-s 输出内部类型签名
-c 输出分解后的代码,例如,类中每一个方法内,包含java字节码的指令,
-verbose 输出栈大小,方法参数的个数
java编译器输出的指令流,基本上是基于栈的指令集架构,指令流里面的指令大部分都是零地址指令,他们依赖操作数栈进行工作。
运行 javap -verbose Test,
public static void main(java.lang.String[]);
Code:
Stack=1, Locals=3, Args_size=1
0: iconst_0 //首先,执行偏移地址为0的地址,把0入栈(栈顶=0),
1: istore_1 //把栈顶的值放到局部变量1中,即i中(i=0,栈顶=0)
2: iload_1 //把局部变量1的值,即0入栈,也就是说此时栈顶的值是0(i=0,栈顶=0)
3: iinc 1, 1 //把局部变量1,也就是i,增加1,这个指令不会导致栈的变化,i此时变成1了(i=1,栈顶=0)
6: istore_1 //把栈顶的值放到局部变量1中,即i中,栈顶的值是0,此时(i=0,栈顶=0)
7: iconst_0 //把0入栈(栈顶=0)
8: istore_2 //把栈顶的值放到局部变量2中,即j中(j=0,栈顶=0)
9: iinc 2, 1 //把局部变量2,也就是j,增加1,这个指令不会导致栈的变化,j此时变成1了
12: iload_2 //把局部变量2的值,即1入栈,此时(j=1,栈顶=1)
13: istore_2 //把栈顶的值放到局部变量2中,即j中(j=1)
14: return
LineNumberTable: