【JVM类加载及字节码技术】栈中的执行过程-构造方法(二)

一、分析案例

通过字节码指令来分析代码。

public class Demo2 {
	public static void main(String[] args) {
		int i=0;
		int x=0;
		while(i<10) {
			x = x++;
			i++;
		}
		System.out.println(x); //结果为0
	}
}

下面我们就通过分析字节码指令:

Code:
     stack=2, locals=3, args_size=1	//操作数栈分配2个空间,局部变量表分配3个空间
        0: iconst_0		//准备一个常数0
        1: istore_1		//将常数0放入局部变量表的1号槽位 i=0
        2: iconst_0		//准备一个常数0
        3: istore_2		//将常数0放入局部变量的2号槽位 x=0	
        4: iload_1		//将局部变量表1号槽位的数放入操作数栈中
        5: bipush        10		//将数字10放入操作数栈中,此时操作数栈中有2个数
        7: if_icmpge     21		//比较操作数栈中的两个数,如果下面的数大于上面的数,就跳转到21。这里的比较是将两个数做减法。因为涉及运算操作,所以会将两个数弹出操作数栈来进行运算。运算结束后操作数栈为空
       10: iload_2			//将局部变量2号槽位的数放入操作数栈中,放入的值是0
       11: iinc          2, 1	//将局部变量2号槽位的数加1,自增后,槽位中的值为1
       14: istore_2		//将操作数栈中的数放入到局部变量表的2号槽位,2号槽位的值又变为了0
       15: iinc          1, 1 	//1号槽位的值自增1
       18: goto          4 	//跳转到第4条指令
       21: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       24: iload_2
       25: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
       28: return

我们这里主要关注第10、11、14条指令iload_2 ,iinc,istore_2,我们能看到:

  1. 首先执行的是加载到操作数栈,iload_2,将x = 0 的值0放入数栈。
  2. 再进行自增 iinc这次自增是在局部变量表x = 1,并不是在数栈,所以数栈中的数仍是0
  3. 最后又将数栈中的数0放入局部变量表x = 0,所以不管运行多少次,x都是0

二、构造方法 cinit( )V、init( )V

1、cinit( )V

public class Demo3 {
	static int i = 10;
	static {
		i = 20;
	}
	static {
		i = 30;
	}
	public static void main(String[] args) {
		System.out.println(i);  //结果为30
	}
}

编译器会按照至上而下的顺序,收集所以static静态代码块静态成员赋值变量的代码,合并为一个特殊的方法cinit()V

stack=1, locals=0, args_size=0
         0: bipush        10
         2: putstatic     #3                  // Field i:I
         5: bipush        20
         7: putstatic     #3                  // Field i:I
        10: bipush        30
        12: putstatic     #3                  // Field i:I
        15: return

2、init( )V

public class Demo4 {
	private String a = "s1";
	{
		b = 20;
	}
	private int b = 10;
	{
		a = "s2";
	}
	public Demo4(String a, int b) {
		this.a = a;
		this.b = b;
	}
	public static void main(String[] args) {
		Demo4 d = new Demo4("s3", 30);
		System.out.println(d.a);
		System.out.println(d.b);
	}
}

编译器会按至上而下的顺序,收集所有 { } 代码块成员变量赋值的代码以及本身存在的构造方法,形成新的构造方法init( )V,但原方法的本身存在的构造方法内的代码总是在后

Code:
     stack=2, locals=3, args_size=3
        0: aload_0
        1: invokespecial #1                  // Method java/lang/Object."<init>":()V
        4: aload_0
        5: ldc           #2                  // String s1
        7: putfield      #3                  // Field a:Ljava/lang/String;
       10: aload_0
       11: bipush        20
       13: putfield      #4                  // Field b:I
       16: aload_0
       17: bipush        10
       19: putfield      #4                  // Field b:I
       22: aload_0
       23: ldc           #5                  // String s2
       25: putfield      #3                  // Field a:Ljava/lang/String;
       //原始构造方法在最后执行
       28: aload_0
       29: aload_1
       30: putfield      #3                  // Field a:Ljava/lang/String;
       33: aload_0
       34: iload_2
       35: putfield      #4                  // Field b:I
       38: return
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值