zoukankan      html  css  js  c++  java
  • 根据字节码探讨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

     

  • 相关阅读:
    斗鱼扩展--localStorage备份与导出(九)
    斗鱼扩展--管理移除房间(八)
    斗鱼扩展--让你看到更多内容(七)
    Ubuntu18.04 安装水星1300M无线网卡
    Course1_Week1_ProgrammingHomeWork
    找出3个数中不为-1的最小数
    马拉车算法
    偏差-方差分解
    决策树如何防止过拟合
    可视化数据集两个类别变量的关系
  • 原文地址:https://www.cnblogs.com/vinozly/p/5401698.html
Copyright © 2011-2022 走看看