Java自增

本文分为以下部分:

栗子

java存在一种神奇的操作符,++,自增1,但是经常分不清楚 i++++i 两者的区别,虽然最后结果可能都是 i+1,但是在不同场景使用有不同效果。先上一段代码。

public class IncreaseTest {

    public static void main(String[] args) {
int i = 10; int j = i++;
System.out.println(j); int k = ++i;
System.out.println(k);
} }

看着脑袋都大,感觉 j、k 最后值都一样,实际上不一样。在讲解原理之前,先简单说明一下底层东西。

局部变量表

oracle java 局部变量表 中解释

其中第二段解释,byte、char、short、int 等基本数据类型值会存在局部变量表中。

操作数栈

oracle java 操作数栈 中解释

简单理解就是 主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间。就是用于计算等操作。

举个简单的栗子简单解释上面两个东西

/**
* 操作数栈压入 10 这个值
* 然后将 10 保存到本地变量表赋值给 i
* j同理
*
* 在进行 k = i + j 的操作
* 操作数栈从本地变量表中读取 i 的值压入操作数栈
* 操作数栈从本地变量表中读取 j 的值压入操作数栈
* 然后对操作数栈中的两个值进行相加操作
* 将结果保存到本地变量表同时赋值给 k
* 最后输出 本地变量表中 读取的数据
*/
public static void main(String[] args) {
int i = 10;
int j = 20;
int k = i + j; System.out.println(k);
}

图例如下:

栗子解释

回归正题,最初的栗子,在计算 j 的时候,是先将 i 的本地变量表的值取出来压入操作数栈,然后再进行 ++ 、赋值等操作,那是先赋值还是先 ++ 呢,其实已经不重要了,因为 ++ 操作操作的是本地变量表的值,而不是操作数栈中的值,所以当 i 的值已经压入操作数栈后,那么操作数栈中的值已经是 10 了,就算本地变量表的值再变化,不会改变操作数栈中的值。所以 j 为 10,本地变量表中 i 为11。(事实上是i的值取出来压入操作数栈,然后i的本地变量表进行+1操作,然后操作数栈赋值给j)

然后第二步,进行的是 int k = ++i;

首先看到的是 ++,所以操作的是本地变量表 i+1 ,然后再将 i 的本地变量表值压入操作数栈,再赋值给 k。

所以 i++ ,是先将 i 的值压入操作数栈,再将本地变量表中 i 的值 +1 ,再将操作数栈中的数值赋值给要赋值的对象。

++i ,是先将本地变量表中 i 的值 +1,再压入操作数栈中,再进行赋值给对象等操作。

简记:先++就是先+1,后++就是后+1。

来点复杂的

public class IncreaseTest2 {

    public static void main(String[] args) {
int i = 10;
i = i++;
System.out.println(i); i = ++i;
System.out.println(i);
} }

首先看 i = i++;

通过简单的栗子,我们知道,当 i++ 再后面时,为后 ++;那么是 i 先赋值给自己 ,再 +1?

当然不是,仔细看上方赋值给 j 的图会发现,先本地变量 +1 ,再进行赋值。

然后再看 ++i,和第一个栗子差不多

字节码解读

第一个栗子

在终端中使用 javap -v -p xxx.class 文件可以看到该class文件的字节码文件。由于不好阅读,所以追加覆盖到 test1.txt 文件中。(采用idea的 jclasslib 插件也可以)

在文件中找到熟悉的public static void main,下面即为代码的字节码,我贴一部分

感觉有点晦涩难懂,我一一解释吧。

bipush 将数值(当前10位byte,-128—127均为byte)压入操作数栈。

istore 将操作数栈栈顶的值弹出返回给本地变量表(保存到本地变量)。

iload 从本地变量表中读取数值压入操作数栈。

iinc 本地变量表中的值+1

0: bipush        10	//操作数栈压入10
2: istore_1 //将10存储到本地变量i (这里1表示i,可以从文件下方LocalVariableTable查看)
3: iload_1 //读取i的值 10 压入操作数栈
4: iinc 1, 1 //本地变量中 i 的值 +1(操作数栈值不变,依旧为10)
7: istore_2 //操作数栈栈顶(10)的值弹出返回本地变量 j ,所以 j 为10 11: iload_2 //有个打印输出流,需要读取 j 的值,删除了相应字节码 15: iinc 1, 1 //本地变量 i 的值 +1(原本为11,现在变为12)
18: iload_1 //读取i的值 12 压入操作数栈
19: istore_3 //保存至 k ,所以 k 为12

第二个栗子

使用同样方法查看字节码

其实和第一个栗子一样,可以自行理解。

特栗

public class IncreaseTest3 {

    public static void main(String[] args) {
int i = 10; i = (i++) * (++i); //120
System.out.println(i);
} }

其实再理解上方字节码或者图解,这个自然而然容易理解了

图解

字节码大概描述就是

iload 	//10 入操作数栈
iinc //本地变量 +1 (操作数栈中依旧为10)
innc //本地变量继续 +1(此时为12)
iload //12 入操作数栈
//然后进行乘法得到120
istore

总结

i++ ,是先将 i 的值压入操作数栈,再将本地变量表中 i 的值 +1 ,最后操作数栈的数进行操作。

++i ,是先将本地变量表中 i 的值 +1,再压入操作数栈中,最后操作数栈的数进行操作。

简单记忆:先++就是先+1,后++就是后+1。

Java自增的更多相关文章

  1. Java自增原子性问题(测试Volatile、AtomicInteger)

    这是美团一面面试官的一个问题,后来发现这是一道面试常见题,怪自己没有准备充分:i++;在多线程环境下是否存在问题?当时回答存在,接着问,那怎么解决?...好吧,我说加锁或者synchronized同步 ...

  2. Java MVC 增删改查 实例

    需求:实现增加新部门的功能,对应数据库表示Oracle的dept表 一.Java MVC 增 实现: 1.视图层(V):注册部门 deptAdd.jsp 在注册新部门页面只需输入“部门名称”和“城市” ...

  3. 根据字节码探讨java自增运算符的原理

    public class Test { static int x, y; public static void main(String args[]) { x++; myMethod(); Syste ...

  4. JAVA自增自减的玄机

    先看下面代码: ; i = i++; System.out.println(i); 请问:输出结果为多少? ---------------------------------------------- ...

  5. Java 自增(++) 和 C语言中自增的区别

    在Java.c语言等高级语言中自增和自减的作用基本一致,都是变量自身加一或减一.下面我只对自增进行说明,自减是类似的. 自增运算符(++),有两种书写形式,一个是在变量前: ++ num; 另一种在变 ...

  6. Java自增和自减操作符——++/--的那些事

    1. 概述 自增操作符(++)和自减操作符(--)是对变量进行加1和减1的操作. 2.分类说明 ++和--是对变量进行自增1和自减1的简写操作符.许多编程任务中经常需要对变量加1或者减1,所以采用这两 ...

  7. java 动态增/减集合元素

    1. 简介 有时候需要在集合遍历过程中进行增/删,下面介绍几种正确的操作方式. 2. 示例 例如有如下集合[1, 2, 2, 3, 5],需要删除被2整除的元素. import java.util.* ...

  8. Java 自增原理

    很多人都知道 i++ 和 ++i 的区别 a = i++: a = i; i = i+1; a = ++ i; i = i + 1; a = i; 但碰到 i = i ++;的时候很多人就懵了? i是 ...

  9. JAVA JDBC 增删改查简单例子

    1.数据库配置文件jdbc.properties driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/test username= ...

  10. java 自增和自减运算符

    /** 自增和自减运算符: ++: 如果是++b,则表示先对变量b+1,再执行其他的操作: 如果是b++,则表示先执行表达式操作,再对变量自身+1 --: 用法和++相同 */ //Test.java ...

随机推荐

  1. How to install Django-Install Python Django | Django 安装指南【官方版】

    How to install Django¶ This document will get you up and running with Django. Install Python--Linux ...

  2. Django框架——csrf跨站请求伪造、csrf校验、csrf相关装饰器、auth认证、auth认证相关模块及操作

    csrf跨站请求伪造 钓鱼网站:模仿一个正规的网站 让用户在该网站上做操作 但操作的结果会影响到用户正常的网站账户 但是其中有一些猫腻 eg:英语四六级考试需要网上先缴费 但是你会发现卡里的钱扣了但是 ...

  3. linux系统关闭指定端口

    linux系统关闭指定端口 关闭指定端口 firewall-cmd --zone=public --remove-port=80/tcp --permanent systemctl restart f ...

  4. 牛客网-SQL专项训练17

    ①SQL查询中使用WHere子句指出的是:查询条件 ②Mysql中表student_table(id,name,birth,sex),查询重复姓名.重复次数,并按重复次数降序排列,正确的是(A)? 解 ...

  5. 5年磨一剑|优酷Android包瘦身治理思路全解

    简介: 稳定性.性能.包大小,在移动端基础用户体验领域"三分天下",是app承载业务获得稳定.高效.低成本.快速增长的重要基石.其中,包大小对下载转化率.拉新拉活成本等方面的影响至 ...

  6. 网易云音乐基于 Flink + Kafka 的实时数仓建设实践

    一.背景介绍 (一)流平台通用框架 目前流平台通用的架构一般来说包括消息队列.计算引擎和存储三部分,通用架构如下图所示.客户端或者 web 的 log 日志会被采集到消息队列:计算引擎实时计算消息队列 ...

  7. 阿里巴巴云原生混部系统 Koordinator 正式开源

    ​简介: 脱胎于阿里巴巴内部,经过多年双 11 打磨,每年为公司节省数十亿的混部系统 Koordinator 今天宣布正式开源.通过开源,我们希望将更好的混部能力.调度能力开放到整个行业,帮助企业客户 ...

  8. Python编程的若干个经典小技巧

    1. 原地交换两个数字 Python 提供了一个直观的在一行代码中赋值与交换(变量值)的方法,请参见下面的示例: x,y= 10,20 print(x,y) x,y= y,x print(x,y) # ...

  9. PHP vs Golang ? 想什么呢 ! What Are You Thinking !

    在使用 PHP 多年之后,我对 PHP 的优势和劣势已经非常清楚,与后起之秀 Golang 相比,两者已经不在一个重量级. PHP 更像是 70 kg 级别的选手,脚本语言,极速开发,部署方便,性能可 ...

  10. dotnet 推荐 LightWorkFlowManager 轻量的工作过程管理库

    本文将和大家推荐我团队开源的 LightWorkFlowManager 轻量的工作过程管理库,适合任何需要执行工作过程的应用逻辑,可以方便将多个工作过程拼凑起来,且自动集成重试和失败处理,以及日志和上 ...