简单的main方法字节码学习

2018-05-11  本文已影响65人  上重楼

java源码如下:

   public static void main(String[] args) {
       int a = 10;
       int b = 1000;
       System.out.println(add(a, b));
   }

   public static int add(int a, int b) {
       int c = a + b;
       return c;
   }

解析字节码后:

public class Taaa {
 public Taaa();
   Code:
      0: aload_0    //将局部变量表0号位置(this)入栈  实例方法局部变量表的第一个元素一定是对象的引用(this)
      1: invokespecial #1              // Method java/lang/Object."<init>":()V 调用私有的实例化方法
      4: return

 public static void main(java.lang.String[]);
   Code:
      0: bipush        10                  //将操作数10转为int类型入栈,就是源码里的变量a
      2: istore_1                            //将操作数栈 栈顶元素加载到局部变量表索引为1的这个位置
      3: sipush        1000              //将操作数1000转int 入栈,源码里的b
      6: istore_2                           //同 istore_1  只是索引为2
      7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream; 将运行时常量池的#2元素入栈
     10: iload_1                          //读取局部变量表元素1到栈顶
     11: iload_2                           //读取局部变量表元素2到栈顶
     12: invokestatic  #3                  // Method add:(II)I  调用静态方法add
     15: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V 调用输出 
     18: return

 public static int add(int, int);
   Code:
      0: iload_0     //在add这个方法里面,有一个新的局部变量和新的操作数栈,所以源码里的a和b分别作为局部变量表的0和1元素,这行是加载第0个元素到栈顶
      1: iload_1   //这行是加载第1个元素到栈顶
      2: iadd       //将栈的最前面2个元素相加 将结果入栈(栈顶)
      3: istore_2  //将栈顶元素存入局部变量表第2个位置
      4: iload_2   //读取局部变量表第2个位置的元素加载到栈顶
      5: ireturn   //返回栈顶的int类型数据
}

这里有几个小细节,在源码同样都是int类型的 a 和b 在字节码分别用 bipush sipush载入。说明源码里的值被按照其取值范围窄化为小类型了。

局部变量表和操作数栈在每个方法被调用的时候创建,方法的参数顺序就是加入到局部变量表的顺序,比如add方法,a存在局部变量表的0位置,b存在1位置

每一行字节码开头的数值是本行相对于方法起始处的字节偏移量

静态方法局部变量表从0开始,方法的入参依次存入。
实例方法局部变量表从1开始,方法的入参从1开始存。0存了对象的引用

add方法偏移3、4那2行, 先将计算结果从栈顶存入局部变量表,又从局部变量表加载到栈顶,然后才返回栈顶。看上去是在重复计算,是因为源码没有直接 return a+b;
而这个字节码还没经过jvm的优化,只是完完全全的翻译源代码。所以写代码的时候尽量简单点。

上一篇下一篇

猜你喜欢

热点阅读