对于 ++i 和 i++,许多人可能都知道,不就是先加1再取值,和先取值再加1嘛。然而,真的是这样吗?请先看以下4道题,能全部答对可以忽略这篇文章。

题目

// 示例1
int i = 1;
i = i++;
System.out.println("i = " + i); // 示例2
int i = 1;
int j = (2 * i++) + i;
System.out.println("j = " + j); // 示例3
int i = 1;
int j = i + (2 * i++);
System.out.println("j = " + j); // 示例4
int i = 1;
int j = 1;
int k = i++ + ++i + ++j + j++;
System.out.println("k = " + k);

先别着急着看答案,先自己思考下,解出自己的答案,然后再往下翻查看答案是否与你的一致。

答案

示例1:i = 1
示例2:j = 4
示例3:j = 3
示例4:k = 8

你是否发现有些答案和你想的不一样,如果我告诉你 ++i 和 i++ 其实都是先计算加1,你是不是更懵逼了!再详解答案之前,先了解两个知识点。

1 i++ 和 ++i 原理

  • i++:先自增,再返回自增之前的值
  • ++i:先自增,再返回自增之后的值
  • 不论是前++还是后++,它们的共同点就是先自增

2 表达式原则

一个变量也是表达式,多个表达式的加减法运算都是从左到右进行的,当然乘除法的优先级还是大于加减法的。

答案详解

// 示例1 结果:i = 1
int i = 1;
i = i++;
System.out.println("i = " + i);

根据原理,先自增,再返回自增之前的值,i 自增后,i = 2,然后返回自增之前的值1,此时表达式变成 i = 1,1没赋值给 i 时 i 的值是2,但最后把1赋值给 i 时,i 的值就又变成1了。

// 示例2 结果:j = 4
int i = 1;
int j = (2 * i++) + i;
System.out.println("j = " + j);

根据表达式原则,一个变量也是表达式,多个表达式的加减法运算都是从左到右进行的

  1. 优先运算左边的表达式,即(2 * i++),i++后,i 的值为2,并返回自增之前的值1
  2. 此时表达式为 int j = (2 * 1) + i ,i 的值已经是2了
  3. 最后表达式变为 int j = (2 * 1) + 2 ,于是 j = 4。
// 示例3 结果:j = 3
int i = 1;
int j = i + (2 * i++);
System.out.println("j = " + j);

按数学思维,我们可能会先计算 2 * i++ 部分,i 先自增 i = 2,然后返回自增之前的值1,此时表达式变为 int j = i + (2 * 1) 。此时 i 的值为2了,故表达式又变为 int j = 2 + (2 * 1) ,结果 j = 4,然而这答案是错误的。正确逻辑如下:

根据表达式原则,一个变量也是表达式,多个表达式的加减法运算都是从左到右进行的

  1. int j = i + (2 * i++) 先算 + 号左边 i 这个表达式,表达式的结果为1
  2. 表达式变为 j = 1 + (2 * i++)
  3. 再计算 + 号右边的表达式,然后 i 自增并返回自增之前的值1,表达式又变为 j = 1 + (2 * 1)
  4. 最终结果为 j = 3,此时 i 的值为2
// 示例4 结果:k = 8
int i = 1;
int j = 1;
int k = i++ + ++i + ++j + j++;
System.out.println("k = " + k);
  1. 先计算 i++,i++ 之后 i 的值为2,并返回自增之前的值1,表达式变为 1 + ++i + ++j + j++。此时的 i 值为2
  2. 再计算 ++i,++i 之后 i 的值为3,并返回自增之后的值3,表达式变为 1 + 3 + ++j + j++。此时 i 的值为3
  3. 再计算 ++j,++j 之后 j 的值为2,并返回自增之后的值2,表达式变为 1 + 3 + 2 + j++。此时 j 的值为2
  4. 再计算 j++,j++之后 j 的值为3,并返回自增之前的值2,表达式变为 1 + 3 + 2 +2,即结果为8,此时j的值为3

你真的懂 i++ 和 ++i 吗?的更多相关文章

  1. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  2. 【转】was mutated while being enumerated 你是不是以为你真的懂For...in... ??

    原文网址:http://www.jianshu.com/p/ad80d9443a92 支持原创,如需转载, 请注明出处你是不是以为你真的懂For...in... ??哈哈哈哈, 我也碰到了这个报错 . ...

  3. javascript的语法作用域你真的懂了吗

    原文:javascript的语法作用域你真的懂了吗 有段时间没有更新了,思绪一下子有点转不过来.正应了一句古话“一天不读书,无人看得出:一周不读书,开始会爆粗:一月不读书,智商输给猪.”.再加上周五晚 ...

  4. 你真的懂ajax吗?

    前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...

  5. “三次握手,四次挥手”你真的懂吗?TCP

    “三次握手,四次挥手”你真的懂吗?  mp.weixin.qq.com 来源:码农桃花源 解读:“拼多多”被薅的问题出在哪儿?损失将如何买单? 之前有推过一篇不错的干货<TCP之三次握手四次挥手 ...

  6. 你真的懂 ajax 吗?

    前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...

  7. 【转】先说IEnumerable,我们每天用的foreach你真的懂它吗?

    [转]先说IEnumerable,我们每天用的foreach你真的懂它吗? 我们先思考几个问题: 为什么在foreach中不能修改item的值? 要实现foreach需要满足什么条件? 为什么Linq ...

  8. 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截

    程序猿修仙之路--数据结构之你是否真的懂数组?   数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构  .要想在之后的江湖历练中通关,数据结构必不可少. ...

  9. C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  10. 你真的懂printf么?

    自从你进入程序员的世界,就开始照着书本编写着各种helloworld,大笔一挥: printf("Hello World!\n"); 于是控制台神奇地出现了一行字符串,计算机一句温 ...

随机推荐

  1. cookie,session,token之间的联系与区别

    发展史 1.很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, 不需要记录谁在某一段时间里都浏览了什么文档,每次请求都是一个新的HTTP协议, 就是请求加响应,  尤其是我不用 ...

  2. Petrozavodsk Summer Training Camp 2016H(多标记线段树)题解

    题意: \(n\)个草,第\(0\)天种下,高度都为\(0\),每个草每天长高\(a_i\).现给出\(q\)询问,每次给出第\(b_i\)天,然后把高于\(d_i\)的全削成\(d_i\),每次问你 ...

  3. 图解 H5 与 WebView 数据通信原理

    图解 H5 与 WebView 数据通信原理 Android / iOS / RN / Flutter H5 接受数据 自定义 schema H5 调用原生 API 拍照,扫码 原生 调用 H5 AP ...

  4. Chrome & targetText

    Chrome & targetText target text http://www.ruanyifeng.com/blog/2019/03/weekly-issue-47.html http ...

  5. foreign language learning

    foreign language learning free online learning websites 多邻国 https://www.duolingo.com 忆术家 https://www ...

  6. 阿里面试这样问:redis 为什么把简单的字符串设计成 SDS?

    2021开工第一天,就有小伙伴私信我,还给我分享了一道他面阿里的redis题(这家伙绝比已经拿到年终奖了),我看了以后觉得挺有意思,题目很简单,是那种典型的似懂非懂,常常容易被大家忽略的问题.这里整理 ...

  7. [转]c++使用thread类时编译出错,对‘pthread_create’未定义的引用

    转载地址:https://blog.csdn.net/wuhui20091515/article/details/52531202 例子1 #include <iostream> #inc ...

  8. Java对象内存布局

    本文转载自Java对象内存布局 导语 首先直接抛出问题 Unsafe.getInt(obj, fieldOffset)中的fieldOffset是什么, 类似还有compareAndSwapX(obj ...

  9. display: inline、block、inline-block、flex和inline-flex

    inline 共享一行 不能修改width.height属性,大小由内容撑开 padding属性 top.right.bottom.left设置都有效:margin属性只有left.right设置有效 ...

  10. 一文学会Dockerfile语法

    接应上篇,续讲前文.今天咱来聊一下Dockerfile的使用 . 虽然可以通过docker commit命令来手动创建镜像,但是通过Dockerfile文件,可以帮助我们自动创建镜像,并且能够自定义创 ...