JAVA字节码(一)

JAVA字节码(一)

例1

public class Helloworld {
	public static void main(String[] args) {
		System.out.println("hello,world");
	}
}

字节码:

public class com.xxx.ch1.Helloworld {
  //构造函数
  public com.xxx.ch1.Helloworld();
    Code:
       //aload_0 : 告诉虚拟机,将局部变量this放入操作栈里(位置0 总是默认留给this)
       0: aload_0
       //调用常量池里(constant pool)的方法
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return
 
  public static void main(java.lang.String[]);
    Code:
       //将静态字段压入操作栈,#16指向了常量池里的  System.out 对象
       0: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       //压入#22所代表的字符串的引用入操作栈
       3: ldc           #22                 // String hello,world
       //调用方法常用的指令
       5: invokevirtual #24                 // Method java/io/PrintStream.println;(Ljava/lang/String;)V
       8: return
}
  1. aload_0

    对于每一个方法(构造函数从字节码角度来讲,也是一个方法,并无区别),方法的参数,以及方法中申明的变量都是在编译期间确定好的,按照出现顺序存放在栈帧里(stack frame)的局部变量表里,位置0 总是默认留给this,其后的位置留给方法的申明参数列表,再之后是留给方法内部用到的局部变量

  2. invokespecial

    指令要求操作栈(Operand Stack)有一个对象引用,也就是 也就是刚通过aload_0压入的this,invokespecial 其后的参数指向常量池的init方法。正如invokespecial 名字所暗示的那样,此指令只用于一些特殊方法调用,如实例的初始化方法,私有方法,父类方法

例2

  public int add(int, int);
   Code:
      0: iload_1
      1: iload_2
      2: iadd
      3: istore_3
      4: iload_3
      5: ireturn
  1. iadd 将操作栈俩个变量想加,i表示操作栈俩个变量是int类型
  2. istore_3 操作栈结构存回到变量表里,位置索引是3,也就是变量c
  3. iload_3 因为方法要求返回值,return指令 仍然需要调用操作栈,所以又将变量3压入操作栈里

例3

public List cast(Object a){
		List list = (List)a;
		return list;
}
public java.util.List cast(java.lang.Object);
  Code:
     0: aload_1
     1: checkcast     #16                 // class java/util/List
     4: astore_2
     5: aload_2
     6: areturn

java虚拟机有3中引用类型,分别是类类型(class Type),接口类型(interface Type),数组类型(arrayType),分别指向了运行时动态创建的类实例,接口实例,以及数组。如指令checkcast,就要求操作栈里存放的是Refernce Type

例4

public static void main(String[] args) {
        int a = 1;
        a = a++;
        int b = a++;
        System.out.println("a="+a);
        System.out.println("b="+b);
    }
// a=2, b=1

字节码

 //将int型常量值1推送至栈顶
 0 iconst_1
 //将栈顶int型数值存入第二个本地变量 a
 1 istore_1
 //将第二个int型本地变量 a 推送至栈顶
 2 iload_1
 //将指定int型变量增加指定值(+1), 之后局部变量 a=2,但是并未压入操作数栈
 3 iinc 1 by 1
 //将栈顶int型数值(1)存入第二个本地变量 a=1
 6 istore_1
 //将第二个int型本地变量 a=1 推送至栈顶
 7 iload_1
 //将指定int型变量增加指定值(+1) a=2
 8 iinc 1 by 1
 //将栈顶int型数值存入第三个本地变量 b=1
11 istore_2
12 return

例5

public static void main(String[] args) {
        int a = 1;
        a = ++a;
        int b = ++a;
//        System.out.println("a="+a);
//        System.out.println("b="+b);
    }
// a=3, b=3

字节码:

 0 iconst_1
 1 istore_1
 2 iinc 1 by 1 // 局部变量 a=2
 5 iload_1  // 压入栈顶:2
 6 istore_1 // 栈顶(2)保存至第二个本地变量 a
 7 iinc 1 by 1 // 本地变量 a + 1, a=3
10 iload_1 // 压入栈顶 a=3
11 istore_2 // 栈顶(3)保存至第三个本地变量 b
12 return

参考
https://blog.csdn.net/xiandafu/article/details/51458791

发布了18 篇原创文章 · 获赞 0 · 访问量 271

猜你喜欢

转载自blog.csdn.net/shijyuan/article/details/104642240
今日推荐