java字节码《java虚拟机》要点精炼


本文图片以及部分内容来自Java字节码增强探秘
Java字节码的介绍

字节码基础

.java文件通过javac编译后将得到一个.class文件,如下图所示,class文件中都是16进制数。
在这里插入图片描述
java字节码主要包括以下几部分。
在这里插入图片描述
(1)魔数,魔数固定的值是CAFEBABY,占用四个字节,用此来判断该文件是否可以被虚拟机所接收。我理解在类加载过程中,校验的第一步格式校验就是去校验魔数。

补充:为什么CA占一个字节呢,因为一个字节是8位01,而这个是16进制的,最大可以到15,15就是F,也就是1111,所以一个16进制数需要4位01来存储,因此两个16进制数就是一字节。

(2)版本数:紧接着魔数的后4位数就是版本数,虚拟机要求不能执行超过其版本号的class文件。

(3)常量池:常量池中存储的是字面量与符号引用。由于存储的数量不定,因此需要两字节来存储数量。常量池中存储与常规不同,它的存储是以1开始的,因此比如值为0x0016,对应22。常量池中有21个常量,其下标为1-21。
在这里插入图片描述
(4)访问标志:之后的两个字节表示访问标志,包括: 这个Class是类还是接口; 是否定义为public类型; 是否定义为abstract类型; 如果是类的话, 是否被声明为final等。
(5) 当前类名:访问标志后的两个字节,描述的是当前类的全限定名。这两个字节保存的值为常量池中的索引值,根据索引值就能在常量池中找到这个类的全限定名。
(6) 父类名称:当前类名后的两个字节,描述父类的全限定名,同上,保存的也是常量池中的索引值。
(7) 接口信息:父类名称后为两字节的接口计数器,描述了该类或父类实现的接口数量。紧接着的n个字节是所有接口名称的字符串常量的索引值。
(8) 字段表:字段表( field_info) 用于描述接口或者类中声明的变量

字段可以包含字段的作用域(public、private、protected修饰符)、是实例变量还是类变量(static修饰符)、可变性(final)、并发可见性(volatile修饰符,是否强制从主内存读写)、可否被序列化(transient修饰符)、字段数据类型(基本类型、对象、数组)、字段名称
在这里插入图片描述
描述符的作用是用来描述字段的数据类型、 方法的参数列表( 包括数量、 类型以及顺序) 和返回值。
在这里插入图片描述
对应数组的话,int[] 会被描述为[I,而java.lang.String[][]被描述为[[java.lang.String
(9)方法表集合:方法表的结构如同字段表一样, 依次包括了访问标志( access_flags) 、 名称索引( name_index) 、 描述符索引( descriptor_index) 、 属性表集合( attributes) 几项。

字节码指令

我们以这个例子为例。

1 package com.company.niuke;
2
3 public class jvmtest {
4    public static void main(String[]args){
5        int  a  =  1 ;
6        int  b  =  2 ;
7        int  c  =  a  +  b ;
8    }
9}
10

对应的class文件如下,

  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 5 L0
    ICONST_1
    ISTORE 1
   L1
    LINENUMBER 6 L1
    ICONST_2
    ISTORE 2
   L2
    LINENUMBER 7 L2
    ILOAD 1
    ILOAD 2
    IADD
    ISTORE 3
   L3
    LINENUMBER 8 L3
    RETURN
   L4
    LOCALVARIABLE args [Ljava/lang/String; L0 L4 0
    LOCALVARIABLE a I L1 L4 1
    LOCALVARIABLE b I L2 L4 2
    LOCALVARIABLE c I L3 L4 3
    MAXSTACK = 2
    MAXLOCALS = 4

可以看到LINENUMBER代表当前对应的行。

第五行的int a = 1其实对应两个字节码:(1)iconst 1:将整形常量1放入操作数栈。(2)istore 1:在索引为1的位置将第一个操作数出栈(一个int值)并且将其存进本地变量,相当于变量a。

第六行与第五行相似。

而第七行则涉及把a和b从本地变量中取出,放入操作数栈中ILOAD 1

iadd:把操作数栈中的前两个int值出栈并相加,将相加的结果放入操作数栈。

ISTORE 3:将操作数栈中的3从栈中取出并存入本地变量。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章