关于java:从-JVM-层面理解-i-和-i-的真正区别

43次阅读

共计 3423 个字符,预计需要花费 9 分钟才能阅读完成。

前言

如果只用一般的常识解释 i ++ 和 ++ i 的话

  • i++ 先将 i 赋值再 ++
  • ++i 先 ++ 再赋值

然而这简略的答复并不能入吸引面试官的眼球, 如果用 java 字节码指令剖析则成果齐全不同。

代码实现

public class OperandStackTest {
/**
    程序员面试过程中,常见的 i ++ 和 ++i 的区别
     */
    public static void add(){
        // 第 1 类问题:int i1 = 10;
        i1++;
        System.out.println(i1);//11

        int i2 = 10;
        ++i2;
        System.out.println(i2);//11

        // 第 2 类问题:int i3 = 10;
        int i4 = i3++;
        System.out.println(i3);//11
        System.out.println(i4);//10

        int i5 = 10;
        int i6 = ++i5;
        System.out.println(i5);//11
        System.out.println(i6);//11

        // 第 3 类问题:int i7 = 10;
        i7 = i7++;
        System.out.println(i7);//10

        int i8 = 10;
        i8 = ++i8;
        System.out.println(i8);//11

        // 第 4 类问题:int i9 = 10;
        int i10 = i9++ + ++i9;//10+12
        System.out.println(i9);//12
        System.out.println(i10);//22
    }

    public static void main(String[] args) {add();
    }
}

运行后果

字节码指令

通过 javap -v out 目录下的 class 文件名 在终端运行失去如下后果

 public static void add();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=10, args_size=0
         0: bipush        10
         2: istore_0
         3: iinc          0, 1
         6: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
         9: iload_0
        10: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        13: bipush        10
        15: istore_1
        16: iinc          1, 1
        19: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        22: iload_1
        23: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        26: bipush        10
        28: istore_2
        29: iload_2
        30: iinc          2, 1
        33: istore_3
        34: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        37: iload_2
        38: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        41: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        44: iload_3
        45: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        48: bipush        10
        50: istore        4
        52: iinc          4, 1
        55: iload         4
        57: istore        5
        59: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        62: iload         4
        64: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        67: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        70: iload         5
        72: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        75: bipush        10
        77: istore        6
        79: iload         6
        81: iinc          6, 1
        84: istore        6
        86: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        89: iload         6
        91: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        94: bipush        10
        96: istore        7
        98: iinc          7, 1
       101: iload         7
       103: istore        7
       105: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       108: iload         7
       110: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
       113: bipush        10
       115: istore        8
       117: iload         8
       119: iinc          8, 1
       122: iinc          8, 1
       125: iload         8
       127: iadd
       128: istore        9
       130: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       133: iload         8
       135: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
       138: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       141: iload         9
       143: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
       146: return

解释以上运行后果

第一类问题

对应的指令为

先将 i1 的值为 10 入栈(bipush),而后将 int 类型的值从栈中存到局部变量表 0 的地位,而后执行 iinc 将 0 地位的值 +1,而后将局部变量表 0 地位的数入栈执行输入操作

所以 i1 的值为 11

先将 i2 的值为 10 入栈(bipush),而后将 int 类型的值从栈中存到局部变量表 1 的地位,而后执行 iinc 将 1 地位的值 +1,而后将局部变量表 1 地位的数入栈执行输入操作

所以 i2 的值为 11

总结

因为没有赋值操作,区别不大。

第二类问题

先将 i3 入栈存储到局部变量表 2 的地位,而后将它入栈,执行 iinc 将 2 地位的值加一,i4 存储到部分表量表 3 的地位

所以 i3 是 11,i4 还是 10

将 i5 入栈存储到局部变量表 4 的地位,因为是 ++ i 所以先 iinc 将 4 地位的值加一,而后将局部变量表 4 的值入栈,执行赋值操作,所以都是 11

第三类问题

先将 i7 入栈,而后存到局部变量表 6 的地位,先把 i6 入栈,而后把 6 处的值加一,因为又将这个值存储到局部变量表 6 处,所以产生笼罩又把值变为 10。

而 ++ i 不会产生笼罩先执行加一而后再把值入栈,在赋值给局部变量表中,所以 i8 为 11。

第四类问题

先将 i9=10 入栈,而后存在局部变量表 8 的地位

int i10 = i9++ + ++i9;

先 iload 将 8 地位的 i9 入栈而后执行 iinc 将 8 处的 i9 加一, 而后执行 ++i9, 在将 8 处的 i9 加一

此时 i9=10+1+ 1 为 12, 而后将 8 地位的 i9 入栈, 执行 add 将栈中的两 i9 相加, 失去的值存储到局部变量表 9 的地位

所以 i10=10+12(i9++ 后还是 10,++i9 后是 12, 因为执行了两次 iinc 操作)

而后调用虚办法和静态方法, 在将 9 处的值入栈执行输入语句

原文链接:https://blog.csdn.net/demo_yo…

版权申明:本文为 CSDN 博主「石破天惊代码人」的原创文章,遵循 CC 4.0 BY-SA 版权协定,转载请附上原文出处链接及本申明。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2021 最新版)

2. 别在再满屏的 if/ else 了,试试策略模式,真香!!

3. 卧槽!Java 中的 xx ≠ null 是什么新语法?

4.Spring Boot 2.5 重磅公布,光明模式太炸了!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0