`
ZangXT
  • 浏览: 118330 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

i++ ,++i,i=i++的问题

阅读更多

     很经典的无聊问题之一。

 int i=0;
i=i++;
结果i是多少?
这是一个经常被提及的问题,答案一直五花八门。
具体测试一下以说明问题:
代码1:

  1. publicclassTest{
  2. publicstaticvoidmain(String[]args){
  3. inti=0;
  4. i=i++;
  5. System.out.println(i);
  6. }
  7. }

结果i依然是0.分析其反编译后的代码:

  1. publicstaticvoidmain(java.lang.String[]);
  2. Code:
  3. 0:iconst_0 //0放到栈顶
  4. 1:istore_1 //把栈顶的值保存到局部变量1,也就是i中
  5. 2:iload_1 //把i的值放到栈顶,也就是说此时栈顶的值是0
  6. 3:iinc1,1 //注意这个指令,把局部变量1,也就是i,增加1,这个指令不会导致栈的变化,也就是说局部变量1,即i此时为1了。
  7. 6:istore_1 //把栈顶的值(0)保存到局部变量1,也就是让i为0了,所以最后i为0
  8. 7:getstatic#2;//Fieldjava/lang/System.out:Ljava/io/PrintStream;
  9. 10:iload_1
  10. 11:invokevirtual#3;//Methodjava/io/PrintStream.println:(I)V
  11. 14:return

值得注意到是i被修改了两次,第一次是i++;i变为1,最后一次是i=0;所以结果i是0
代码2:

  1. publicclassTest2{
  2. publicstaticvoidmain(String[]args){
  3. inti=0;
  4. intj=0;
  5. j=i++;
  6. System.out.println(i);
  7. System.out.println(j);
  8. }
  9. }

这个结果肯定都知道,i是1,j是0.同样看反编译之后的代码:

  1. publicstaticvoidmain(java.lang.String[]);
  2. Code:
  3. 0:iconst_0
  4. 1:istore_1 //i=0
  5. 2:iconst_0
  6. 3:istore_2 //j=0
  7. 4:iload_1 //把i的值放到栈顶,也就是说此时栈顶的值是0
  8. 5:iinc1,1 //局部变量1加1,也就是让i++了,此时i已经是1了,上面说过,此指令不会导致栈变化
  9. 8:istore_2 //把栈顶的值(注意是0)存入局部变量2,也就是j中,所以j=0
  10. 9:getstatic#2;//Fieldjava/lang/System.out:Ljava/io/PrintStream;
  11. 12:iload_1
  12. 13:invokevirtual#3;//Methodjava/io/PrintStream.println:(I)V
  13. 16:getstatic#2;//Fieldjava/lang/System.out:Ljava/io/PrintStream;
  14. 19:iload_2
  15. 20:invokevirtual#3;//Methodjava/io/PrintStream.println:(I)V
  16. 23:return

很明显可以看出,java是先把i的值取出来放到栈顶,我们可以认为是引入了第三个变量int k=i;然后i++,这时候i为1了,然后让j=k;也就是0.结论,i的++运算是在对j这个变量的赋值之前完成的。

代码3:

  1. publicclassTest3{
  2. publicstaticvoidmain(String[]args){
  3. inti=0;
  4. intj=0;
  5. j=++i;
  6. System.out.println(i);
  7. System.out.println(j);
  8. }
  9. }

结果大家也都知道,i=1,j=1
看操作过程:

  1. publicstaticvoidmain(java.lang.String[]);
  2. Code:
  3. 0:iconst_0
  4. 1:istore_1 //i=0
  5. 2:iconst_0
  6. 3:istore_2 //j=0
  7. 4:iinc1,1 //局部变量i加1,这时候i变成1了 。
  8. 7:iload_1 //把i的值放到栈顶,栈顶的值是1
  9. 8:istore_2 //j=1
  10. 9:getstatic#2;//Fieldjava/lang/System.out:Ljava/io/PrintStream;
  11. 12:iload_1
  12. 13:invokevirtual#3;//Methodjava/io/PrintStream.println:(I)V
  13. 16:getstatic#2;//Fieldjava/lang/System.out:Ljava/io/PrintStream;
  14. 19:iload_2
  15. 20:invokevirtual#3;//Methodjava/io/PrintStream.println:(I)V
  16. 23:return

对比代码2和代码3,关键的差别就是iload_1 个iinc这两条指令的位置变了。

最后把iinc指令介绍一下:

iinc

Operation

Increment local variable by constant 给局部变量加上一个常量的值

Format

iinc
index
const

Forms

iinc = 132 (0x84)

Operand Stack

No change 操作数栈无变化

Description

The index is an unsigned byte that must be an index into the local variable array of the current frame (§3.6). The const is an immediate signed byte. The local variable at index must contain an int. The value const is first sign-extended to an int, and then the local variable at index is incremented by that amount.

Notes

The iinc opcode can be used in conjunction with the wide instruction to access a local variable using a two-byte unsigned index and to increment it by a two-byte immediate value.

 


      很多人喜欢拿这个问题和C,C++中的情形来对比。其实在C/C++中这个问题是无任何意义的(当然,在java中也没有什么意义),因为C/C++的标准里并没有规定具体该怎么处理这类表达式,所以不同的编译器有不同的编译结果,而java语言规范却详细规定了表达式的提取规则,不会出现依赖于编译器的问题(假设所有java编译器都遵守规范)。

分享到:
评论

相关推荐

    java中for(int i= 0; i<=10;i=i++)System.out.print(i);为什么无限输出0

    为了避免无限循环的发生,正确的做法是直接使用`i++`或者`i += 1`来更新循环变量: ```java public class Test { public static void main(String[] args) { for (int i = 0; i &lt;= 10; i++) { System.out.print...

    如何理解i=i++和i=++i.docx

    如何理解i=i++和i=++i.docx

    对于含有n个内节点的二元树,证明E=I+2n。其中E、I分别为外部和内部路径长度。

    ### 对于含有n个内节点的二元树,证明E=I+2n。其中E、I分别为外部和外部路径长度。 #### 背景知识 在计算机科学中,二叉树是一种重要的数据结构,它由节点组成,每个节点最多有两个子节点。二叉树在算法设计和分析...

    关于i++和++i以及左值,右值

    因此,如果我们将i++放入表达式中,例如`int c = i++;`,那么变量c将会获得i的原始值,而i在赋值后才会增加。而++i是前缀自增运算符,它先将变量i的值加1,然后返回自增后的值。如果我们使用++i,如`int c = ++i;`,...

    【驱动程序】USBCAN-I_I+_II_II+_2A_I-MINI驱动安装.zip

    本篇将详细介绍"USBCAN-I/I+ II/II+ 2A I-MINI"驱动的安装过程,以及其在不同Windows操作系统(包括win10、win7、win8)下的兼容性问题。 USBCAN-I/I+ II/II+ 2A I-MINI是一款由周立功公司研发的专业CAN总线接口...

    详解Python中表达式i += x与i = i + x是否等价

    在Python编程语言中,`i += x` 和 `i = i + x` 两种表达式在大部分情况下是等价的,但在处理可变对象(如列表)时,它们的行为有所不同。这个问题的关键在于理解Python中的可变对象和不可变对象的概念,以及它们如何...

    matlab代码

    一个小程序kb=200;... if i+4==6||i+4==7||i+4==10||i+4==11 a(i+4,i)=-kd; else a(i+4,i)=-kb; end end for i=1:12 if i==6||i==7||i==10||i==11 a(i,i+4)=-kd; else a(i,i+4)=-kb; end end

    java代码-int i = 0; int s = (++i)+(i--)+i; System.out.println(s);

    2. 后减操作符(i--):这个操作符先返回`i`当前的值,然后将`i`的值减少1。 3. 表达式求值顺序:在Java中,没有明确的顺序来规定带有多个操作符的表达式应该从左到右还是从右到左执行。但根据Java的运算符优先级,...

    C语言中++i与i++的区别.docx

    在C语言中,`++i` 和 `i++` 是两种常见的自增操作符,它们在编程中的作用是增加变量的值。虽然它们看似相似,但在某些特定情况下,两者的行为是有区别的,这也是C语言初学者经常感到困惑的地方。本文将深入探讨这两...

    java代码-i=3; a=i++; i+=a; \u6c42i=

    i+=a;`涉及到了几个核心的编程概念。首先,`i=3;`是一个基本的变量赋值操作,其中变量`i`被初始化为整数值3。在Java语言中,变量的声明和初始化是程序运行的基础,它们为程序提供运行所需的存储空间和初始状态。 ...

    浅析PHP中的i++与++i的区别及效率

    看一些视频教程里面写for循环的时候都是写 ++i 而不是 i++,上网搜索了一下,原来有效率问题 ++i相当于下列代码 i += 1; return i; i++相当于下列代码 j = i; i += 1; return j; 当然如果编译器会将这些差别都...

    测试i++和++i的区别

    使用++i和i++可以使迭代操作变得容易,但是两者到底区别在哪可以从这个程序中得知,使用java语言编写

    快速区分一元运算符i++和++i.docx

    在JavaScript编程语言中,一元运算符`i++`和`++i`是常见的自增操作,它们在处理变量的值时有不同的行为和顺序。理解这两种运算符的区别对于编写高效和无误的代码至关重要。 首先,`i++`称为后置自增运算符。它的...

    表白代码,c#程序员

    i += 0.2) { t = i / Math.PI; x = 16 * Math.pow(Math.sin(t), 3); y = 13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t); points.push(new Point(x, y)); } this.points =...

    数据结构(Java)复习题

    i++) for (j=0;j; j++) A[i][j]=0; 8. 分析下面算法(程序段),给出最大语句频度 ,该算法的时间复杂度是__ __。 for (i=0;i;i++) for (j=0; j&lt;i; j++) A[i][j]=0; 9. 分析下面算法(程序段),给出最大语句频度...

    计算 S=1!+2!+3!+...+N! C语言代码

    i++) { S += factorial(i); } printf("S = %d\n", S); return 0; } ``` 这段代码首先定义了一个名为`factorial`的递归函数,用于计算给定数字的阶乘。在`main`函数中,我们读取用户输入的N值,然后通过for...

    字符串拼接+java+实现示例+源代码

    字符串拼接 public class 字符串拼接 { public static void main(String[] args) { int[] arr = {1, 2,3};...i++) { if (i == arr.length-1) { s += arr[i]; }else { s += arr[i]; s += ","; } } s += "]";

    终端实验

    i++){ LED_PORT0=0xf0;time(300); LED_PORT0=0xff;time(300); } EA=1; } void exint1()interrupt 2{ uchar i; EA=0; for(i=0;i;i++){ LED_PORT2=0xf0;time(300); LED_PORT2=0xff;time(300); } ...

    I+关系网络分析用户指南.docx

    I+关系网络分析用户指南I+3ÍƸå-ƵɑsɫʉɾȳðƧƊ¹ʶǑĪºtˣȎ-Ɵ?ăÜw ̐ĭǺİȨ-±Ǫˊ±Vĸ±Ǽ̝ɜ͋ƒȷǭ̀ÄqĀɎ ȅs̟ʬ`̵/ʓʉɜʬƕZƨTʺ{Ʈǡ

    浅析PHP中的i++与++i的区分及效率_.docx

    i++ 运算符 i++ 运算符是后缀递增运算符,它的执行顺序如下: 1. 返回当前变量的值 2. 将变量的值加 1 例如,以下代码: ```php $i = 5; echo $i++; // 输出 5 echo $i; // 输出 6 ``` ++i 运算符 ++i 运算符...

Global site tag (gtag.js) - Google Analytics