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自增运算符的原理的更多相关文章

  1. 从字节码看java中 this 的隐式传参

    从字节码看java中 this 隐式传参具体体现(和python中的self如出一辙,但是比python中藏得更深),也发现了 static 与 非 static 方法的区别所在! static与非s ...

  2. 从字节码看java类型转换【 深入理解 (T[]) new Object[size] 】

    我们都知道,java中对类型的检查是很严格的,所以我们平操作时,也往往很小心. 如题: (T[]) new Object[size],这种写法是一般我们是不会干的!但是有点经验的同学,还是会遇到这样写 ...

  3. 透过字节码分析java基本类型数组的内存分配方式。

    我们知道java中new方式创建的对象都是在堆中创建的,而局部变量对应的值存放在栈上.那么java中的int [] arr={1,2,3}是存放在什么地方的呢,int []arr = new int[ ...

  4. 通过字节码分析java中的switch语句

    在一次做题中遇到了switch的问题,由于对switch执行顺序的不了解,在这里简单的通过字节码的方式理解一下switch执行顺序(题目如下): public class Ag{ static pub ...

  5. 通过字节码分析Java方法的静态分派与动态分派机制

    在上一次[https://www.cnblogs.com/webor2006/p/9723289.html]中已经对Java方法的静态分派在字节码中的表现了,也就是方法重载其实是一种静态分派的体现,这 ...

  6. 通过字节码分析Java异常处理机制

    在上一次[https://www.cnblogs.com/webor2006/p/9691523.html]初步对异常表相关的概念进行了了解,先来回顾一下: 其源代码也贴一下: 下面来看一下jclas ...

  7. 透过字节码分析Java动态代理机制。

    一.创建动态代理代码 1.创建接口 public interface Subject { void request(); } 2.创建接口实现类 public class RealSubject im ...

  8. 字节首推Java成长笔记:(原理+应用+源码+调优全都有)直接复盘

    今天这篇文章我为了帮助小伙伴们快速构建Java技术栈,这份笔记包含了Java技术点的答案,面经,笔记,希望大家看完可以在短期内容快速面试复盘,达到事半功倍! 本来想将文件上传到开源网站上去,但是文件太 ...

  9. python字节码,java字节码,十六进制相互转换

    下面是互相转换的代码: 有想要了解更多关于python知识的请在下方评论或私信小编

随机推荐

  1. SQL Server 2008 R2中,变表的右键弹出菜单中的“选择前1000行”为“选择所有行”

    原文:SQL Server 2008 R2中,变表的右键弹出菜单中的"选择前1000行"为"选择所有行" 从SQL Server 2008开始,微软为了提高查询 ...

  2. 探讨javascript面向对象编程

    (个人blog迁移文章.) 前言: 下面将探讨javascript面向对象编程的知识. 请不要刻意把javascript想成面向对象编程是理所当然的. javascript里面,对象思想不可少,但是不 ...

  3. POI操作Excel详细解释,HSSF和XSSF两种方式

    HSSF道路: package com.tools.poi.lesson1; import java.io.FileInputStream; import java.io.FileNotFoundEx ...

  4. 宿主机跟Vmware中的linux使用host-only,bridge 方式通信

    声明:我的机器在本文中叫 宿机,vmware中的linux就叫linux 本文已经实现了通过host-only模式 宿机 ping通 linux,但是在host-only模式下,linux 没有pin ...

  5. Oracle表介绍--簇表

    簇和簇表       簇其实就是一组表,是一组共享相同数据块的多个表组成. 将经常一起使用的表组合在一起成簇可以提高处理效率.       在一个簇中的表就叫做簇表.建立顺序是:簇→簇表→数据→簇索引 ...

  6. CRM2011 concurrency问题及解决方案

    CRM2011对删除和添加操作会自动做判断,比如A打开纪录x,B也打开纪录x,然后B删除了纪录x,A去更新的话就会有提示.更新的话是后者覆盖前者,比如A打开纪录x,B打开纪录x,然后B把记录x中的字段 ...

  7. Node填坑教程——简易http服务器

    我们这一期做一个简易的http服务器. 先建一个文件夹,就算是一个空的项目了.然后新建app.js和package.json文件. 这样一个简易项目的基本文件就建好了. 通过命令行工具,在项目路径下输 ...

  8. DHTML【3】--HTML

    从这一节开始我们就开始介绍HTML的标签了,首先我们来介绍Form标签. Form标签也称Form表单,From是与服务器交互最重要的标签,此标签必须做到随手就写,写完就正常运行的地步. 那么什么是F ...

  9. Bootstrap 网格系统

    自版本 2.3.2 起,Bootstrap 提供了两种类型的网格,默认网格系统和流动网格系统.默认的网格系统是 940px 宽和 12 列.本文主要讲解第一种. 首先让我们看,怎么来应用默认网格系统 ...

  10. 《剑指Offer》面试题-从头到尾打印链表

    题目描述: 输入一个链表,从尾到头打印链表每个节点的值. 输入: 每个输入文件仅包含一组测试样例.每一组测试案例包含多行,每行一个大于0的整数,代表一个链表的节点.第一行是链表第一个节点的值,依次类推 ...