根据字节码探讨java自增运算符的原理
- public class Test {
- static int x, y;
- public static void main(String args[]) {
- x++;
- myMethod();
- System.out.println(x + y + ++x);
- }
- public static void myMethod() {
- y = x++ + ++x;
- }
- }
如果以上代码的结果你很自信能做对,那么本文或许对你帮助不大,但仍然可以看下java底层的实现.在最后将给出以上代码的结果以及解析.
本文中的例子主要针对以下情况:
①x=y++
②x=++y
③x=x++
④x=++x
a:x,y为形参
b:x,y为成员变量
废话不多说,直接上代码
代码1(①+b):
- public class Test {
- static int x,y;
- public static void main(String args[]){
- test();
- }
- public static void test(){
- x = y++;
- System.out.println(x+""+y);
- }
- }
结果:01
test()字节码:
- 0: getstatic #3 // Field y:I
- 3: dup
- 4: iconst_1
- 5: iadd
- 6: putstatic #3 // Field y:I
- 9: putstatic #4 // Field x:I
- 12: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
- 15: getstatic #4 // Field x:I
- 18: invokevirtual #6 // Method java/io/PrintStream.println:(I)V
- 21: return
解释:
0:y(值)入操作栈
3:得到y(值)的一个快照y'(值)
(个人认为相当于是将栈顶元素也就是y(值)复制了一份,然后将复制得到的y'(值)入操作栈,现在操作栈中有y(值)和y'(值))
4:常量1入操作栈
5:常量1和y'(值)弹出栈,进行加操作,并将结果s入栈
6:将结果s弹出栈,赋给y(变量)(此时y==1)
9:将y(值)弹出栈,赋给x(变量)(此时x==0)
因为y(值)入操作栈之后没有修改,所以x依旧是0,而y变成了1
代码2(②+b):
- public class Test {
- static int x,y;
- public static void main(String args[]){
- test();
- }
- public static void test(){
- x = ++y;
- System.out.println(x+""+y);
- }
- }
结果11
test()字节码:
- 0: getstatic #3 // Field y:I
- 3: iconst_1
- 4: iadd
- 5: dup
- 6: putstatic #3 // Field y:I
- 9: putstatic #4 // Field x:I
- 12: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
- 15: getstatic #4 // Field x:I
- 18: invokevirtual #6 // Method java/io/PrintStream.println:(I)V
- 21: return
解释:
0:y(值)入操作栈
3:常量1入操作栈
4:常量1和y(值)弹出栈,进行加操作,并将结果s入栈
5:得到栈顶元素也就是s的快照s',并入操作栈
6:将s'弹出栈,并赋给y(变量)(此时y==1)
9:将s弹出栈,并赋给x(变量)(此时x==1)
代码3(③+b):
- public class Test {
- static int x;
- public static void main(String args[]){
- test();
- }
- public static void test(){
- x = x++;
- System.out.println(x);
- }
- }
结果:0
test()字节码:
- 0: getstatic #3 // Field x:I
- 3: dup
- 4: iconst_1
- 5: iadd
- 6: putstatic #3 // Field x:I
- 9: putstatic #3 // Field x:I
- 12: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
- 15: getstatic #3 // Field x:I
- 18: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
- 21: return
解释:
0:x(值)入操作栈
3:得到x(值)的快照x',入操作栈
4:常量1入操作栈
5:常量1和x'弹出操作栈,进行加操作,将结果s入操作栈
6:将s弹出栈,并赋给x(变量)(此时x==1)
9:将x(值)弹出栈,并赋给x(变量)(此时x的值被覆盖,x==0)
代码4(④+b):
- public class Test {
- static int x;
- public static void main(String args[]){
- test();
- }
- public static void test(){
- x = ++x;
- System.out.println(x);
- }
- }
结果:1
test()字节码:
- 0: getstatic #3 // Field x:I
- 3: iconst_1
- 4: iadd
- 5: dup
- 6: putstatic #3 // Field x:I
- 9: putstatic #3 // Field x:I
- 12: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
- 15: getstatic #3 // Field x:I
- 18: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
- 21: return
解释:
0:x(值)入操作栈
3:常量1如入操作栈
4:常量1和x(值)弹出操作栈,进行加操作,并将结果s入操作栈
5:得到栈顶元素s的快照s',入操作栈
6.将s'弹出操作栈,并赋给x(变量)(此时x==1)
9:将s弹出操作栈,并赋给x(变量)(此时x==1)
代码5(①+a):
- public class Test {
- public static void main(String args[]){
- test(0,0);
- }
- public static void test(int x,int y){
- x = y++;
- System.out.println(x+""+y); } }
结果:01
test()字节码:
- 0: iload_1
- 1: iinc 1, 1
- 4: istore_0
- 5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
- 8: new #4 // class java/lang/StringBuilder
- 11: dup
- 12: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
- 15: iload_0
- 16: invokevirtual #6 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
- 19: ldc #7 // String
- 21: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
- 24: iload_1
- 25: invokevirtual #6 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
- 28: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
- 31: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
- 34: return
解释:
0:将本地变量区的y(值)入操作栈
1:将本地变量y加1(y==1)
4:将0中的y(值)弹出栈,并赋给本地变量区的x(x==0)
代码6(②+a):
- public class Test {
- public static void main(String args[]){
- test(0,0);
- }
- public static void test(int x,int y){
- x = ++y;
- System.out.println(x+""+y);
- }
- }
结果:11
test()字节码:
- 0: iinc 1, 1
- 3: iload_1
- 4: istore_0
- 5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
- 8: new #4 // class java/lang/StringBuilder
- 11: dup
- 12: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
- 15: iload_0
- 16: invokevirtual #6 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
- 19: ldc #7 // String
- 21: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
- 24: iload_1
- 25: invokevirtual #6 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
- 28: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
- 31: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
- 34: return
解释:
0:将本地变量y加1(此时y==1)
3:将本地变量y(值)入操作栈
4:将y(值)弹出操作栈,并赋给x(此时x==1)
代码7(③+a):
- public class Test {
- public static void main(String args[]){
- test(0);
- }
- public static void test(int x){
- x = x++;
- System.out.println(x);
- }
- }
结果:0
test()字节码:
- 0: iload_0
- 1: iinc 0, 1
- 4: istore_0
- 5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
- 8: iload_0
- 9: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
- 12: return
解释:
0:本地变量x(值)入操作栈
1:本地变量x加1(此时x==1)
4:将x(值)弹出栈,并赋给本地变量x(此时x==0)
代码8(④+a):
- public class Test {
- public static void main(String args[]){
- test(0);
- }
- public static void test(int x){
- x = ++x;
- System.out.println(x);
- }
- }
结果:1
test()字节码:
- 0: iinc 0, 1
- 3: iload_0
- 4: istore_0
- 5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
- 8: iload_0
- 9: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
- 12: return
解释:
0:本地变量x加1(此时x==1)
3:本地变量x(值)入操作栈
4:将x(值)弹出操作栈,并赋给x(此时x==1)
事实上i++和++i在底层的实现都是先自增,区别在于返回值.i++返回自增前的值,++i返回自增后的值
现在来看看一开始那段代码的结果和解析:
结果:11
myMethod()字节码:
- 0: getstatic #2 // Field x:I
- 3: dup
- 4: iconst_1
- 5: iadd
- 6: putstatic #2 // Field x:I
- 9: getstatic #2 // Field x:I
- 12: iconst_1
- 13: iadd
- 14: dup
- 15: putstatic #2 // Field x:I
- 18: iadd
- 19: putstatic #5 // Field y:I
- 22: return
解释:
0:变量x(值)入操作栈(栈状态:x0)
3:得到栈顶元素x(值)的快照x'(值),并入操作栈(栈状态:x0->x0')
4:常量1入操作栈(栈状态:x0->x0'->1)
5:常量1和x'(值)弹出操作栈,进行加操作,将结果s0入操作栈(栈状态:x0->s0)
6:弹出s0,并赋给x(变量)(栈状态:x0,此时x(变量)==2)
9:将修改后的x(值)入操作栈(栈状态:x0->x1)
12:常量1入操作栈(栈状态:x0->x1->1)
13:常量1和X1(值)弹出操作栈,进行加操作,将结果s1入操作栈(栈状态:x0->s1)
14:得到栈顶元素s1(值)的快照s1'(值),并入操作栈(栈状态:x0->s1->s1')
15:弹出s1'并赋给x(变量)(栈状态:x0->s1)
18:s1和x0弹出栈,进行加操作,将结果s2入栈(栈状态:s2)
19:弹出s2,并赋给y(变量)
所以在myMethod之后x的值为经过两次自增后的值,为x+2==3,而y的值为x0+s1,其中x0为最初传进来的值==1,s1是x经过两次自增后的值==3,所以y==4
x==3,y==4
最后输出的结果就是3+4+4==11
转载请注明出处:http://www.cnblogs.com/vinozly/p/5401698.html
根据字节码探讨java自增运算符的原理的更多相关文章
- 从字节码看java中 this 的隐式传参
从字节码看java中 this 隐式传参具体体现(和python中的self如出一辙,但是比python中藏得更深),也发现了 static 与 非 static 方法的区别所在! static与非s ...
- 从字节码看java类型转换【 深入理解 (T[]) new Object[size] 】
我们都知道,java中对类型的检查是很严格的,所以我们平操作时,也往往很小心. 如题: (T[]) new Object[size],这种写法是一般我们是不会干的!但是有点经验的同学,还是会遇到这样写 ...
- 透过字节码分析java基本类型数组的内存分配方式。
我们知道java中new方式创建的对象都是在堆中创建的,而局部变量对应的值存放在栈上.那么java中的int [] arr={1,2,3}是存放在什么地方的呢,int []arr = new int[ ...
- 通过字节码分析java中的switch语句
在一次做题中遇到了switch的问题,由于对switch执行顺序的不了解,在这里简单的通过字节码的方式理解一下switch执行顺序(题目如下): public class Ag{ static pub ...
- 通过字节码分析Java方法的静态分派与动态分派机制
在上一次[https://www.cnblogs.com/webor2006/p/9723289.html]中已经对Java方法的静态分派在字节码中的表现了,也就是方法重载其实是一种静态分派的体现,这 ...
- 通过字节码分析Java异常处理机制
在上一次[https://www.cnblogs.com/webor2006/p/9691523.html]初步对异常表相关的概念进行了了解,先来回顾一下: 其源代码也贴一下: 下面来看一下jclas ...
- 透过字节码分析Java动态代理机制。
一.创建动态代理代码 1.创建接口 public interface Subject { void request(); } 2.创建接口实现类 public class RealSubject im ...
- 字节首推Java成长笔记:(原理+应用+源码+调优全都有)直接复盘
今天这篇文章我为了帮助小伙伴们快速构建Java技术栈,这份笔记包含了Java技术点的答案,面经,笔记,希望大家看完可以在短期内容快速面试复盘,达到事半功倍! 本来想将文件上传到开源网站上去,但是文件太 ...
- python字节码,java字节码,十六进制相互转换
下面是互相转换的代码: 有想要了解更多关于python知识的请在下方评论或私信小编
随机推荐
- 数以百万计美元的融资YO是什么东东?
给自己做个广告哈,新栏目"面试"已经推出,回复"面试"就可以获取. 这两天最火的应用是什么.非yo莫属,堪称史上最简单的社交应用,仅仅能向好友发送一个yo. 出 ...
- [译]ava 设计模式之享元
(文章翻译自Java Design Pattern: Flyweight) 享元模式用于最小化内存开销.它做的就是使用其他相似的对象尽可能多的分享数据. 1.享元模式类图 2.享元模式Java代码 / ...
- Ubuntu12.04环境搭建遇到的问题和建议(一个)
后的新公司需要在Ubuntu12.04在结构Android开发环境,在这个过程中,我们还是会遇到很多问题,这里记录.为了方便自己的未来,有人谁需要参考.从网络! 1. Q:在终端: sudo apt- ...
- solr的配置文件及其含义
solr与.net系列课程(二)solr的配置文件及其含义 solr与.net系列课程(二)solr的配置文件及其含义 本节内容还是不会涉及到.net与数据库的内容,但是不要着急,这都是学时s ...
- WCF总结笔记
------------------------windowform承载服务步骤: (1)定义契约: using System; using System.Collections.Generic; u ...
- javaFile循环列出指定目录下的所有文件(源代码)
package javatest.basic22; import java.io.File; import java.io.IOException; public class FileTest { p ...
- xmlDom
加载并解析xml文件: <script type="text/javascript"> try //Internet Explorer { xmlDoc=new Act ...
- 运动检测(前景检测)之(一)ViBe
运动检测(前景检测)之(一)ViBe zouxy09@qq.com http://blog.csdn.net/zouxy09 因为监控发展的需求,目前前景检测的研究还是很多的,也出现了很多新的方法和思 ...
- c# 控制职能运行单一实例,再次运行显示已经运行的实例
有这么个需求,软件只能运行一个实例,软件运行后可以让其隐藏运行 再次运行这个软件的时候就让正在运行的实例显示出来 ================================= 当软件隐藏后没办法 ...
- 企业架构研究总结(45)——企业架构与建模之使用ArchiMate进行分析(全系列完)
4. 使用ArchiMate进行分析 正如前面所说的那样,一个企业整体效率的提升有时并不是通过某一个领域内的优化就能达到的,而且这种忽视全局的做法往往还会造成不必要的浪费.由此可见,一个能够跨越各个领 ...