Java字节码 小结

Reference

  • javap 基本用法
  • 深入理解java字节码
  • 从Java代码到字节码
  • Java字节码.class文件案例分析

字节码 核心概念

Class文件是8位字节流,按字节对齐。之所以称为字节码,是因为每条指令都只占据一个字节,所有的操作码和操作数都是按字节对齐的。

数据结构

Java虚拟机规范中规定,Class文件格式采用一种类似C语言结构体的伪结构来存储,它只有两种数据类型

无符号数(基本数据类型)

主要用于描述数字、索引引用、数量值、或UTF-8编码构成的字符串;
u1 – 1个字节
u2 – 2个字节
u4 – 4个字节
u8 – 8个字节

表(复合数据类型)

用于描述有层次关系的复合结构的数据;
习惯性以“_info”结尾

Class文件格式

数据类型 名称 数量
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count + 1
u2 access_flags 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 interfaces interfaces_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods methods_count
u2 attributes_count 1
attribute_info attributes attributes_count

class说明

  • magic: Class文件的头4个字节,它的唯一作用是用于确认该文件是否是能被JVM接受的Class文件
  • minor_version :第5和第6字节是次版本号
  • major_version:第7和第8字节是主版本号

Java字节码 小结_第1张图片

  • constant_pool_count: 常量池大小

  • cp_info : 复合数据结构,是一组常量数据结构,有11种常量数据结构
    Java字节码 小结_第2张图片

  • access_flags :访问标志,access_flags的计算公式为:access_flags = flagA | flagB | flagB …

Java字节码 小结_第3张图片

  • field_info :字段表(field_info)用于描述类或接口中声明的变量,它包含类变量、实例变量,但不包括方法内的局部变量和块变量。和cp_info部分不一样,cp_info因为常量类型的不一样其数据结构有11种,但field_info的结构只有一种。(数据结构如下)
    Java字节码 小结_第4张图片
    字段访问标志,和类的访问标志,因为修饰符不同稍有不同,具体见下图。
    Java字节码 小结_第5张图片

  • method_info:方法表集合(method_info)和字段表集合的结构是一致的,只是访问标志不同。
    Java字节码 小结_第6张图片

  • attribute_info:用于在Class文件、字段表、方法表中携带自己的属性表集合,以用于描述某些场景的专有信息。
    Java字节码 小结_第7张图片
    Java程序方法体里面的代码经过javac编译器处理过后将最终字节码存储在Code属性内。抽象类或接口中的方法不存在Code属性。
    Java字节码 小结_第8张图片

  • SourceFile:SourceFile属性主要记录生成这个Class文件的源代码名称,也属于可选属性,可以使用javac的-g:none或-g:source选项来关闭或要求生成这些信息。

  • LocalVariableTable:LocalVariableTable属性用于描述栈帧中局部变量表中的变量与Java源代码定义的变量之间的关系,但是这种关系并非运行时必须,默认也不会生成到Class文件中,可以通过javac中使用-g:none或-g:vars选项取消或者生成这项信息。

  • LineNumberTable:LineNumberTable属性用于描述Java源代码行号和字节码行号(字节码的偏移量)之间的对应关系,它不是运行时必须属性,但默认会生成到Class文件中。也可以在javac中使用-g:none或-g:lines选项来取消或显示生成这一部分信息。

详细参见 Java字节码.class文件案例分析


jvm运行浅谈

Java虚拟机(JVM)是基于栈结构的。对于最初的main方法产生的所有的方法调用,都会在栈中产生一个帧,这些帧各自包含一组局部变量,这组局部变量就是这个方法在执行过程中所需的所有变量,包括一个指向this的引用、该方法的所有参数以及其他局部定义的变量。对于类方法(即static方法),其参数列表从0开始算起,而对于实例方法,位置0是用来存储this引用。
class运行就是jvm顺序执行一条条保存在Code中的指令,如下所示:
Java字节码 小结_第9张图片

动态过程,如下:

public class Demo {
    public static void foo() {
       int a = 1;
       int b = 2;
       int c = (a + b) * 5;
    }
}

Java字节码 小结_第10张图片

详细参见
- 深入理解java字节码
- 从Java代码到字节码


javap 反汇编

javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码。通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。
语法:
  javap [ 命令选项 ] class…
  javap 命令用于解析类文件。其输出取决于所用的选项。若没有使用选项,javap 将输出传递给它的类的 public 域及方法。javap 将其输出到标准输出设备上。
命令选项
  -help 输出 javap 的帮助信息。
  -l 输出行及局部变量表。
  -public 只显示 public 类及成员。
  -protected 只显示 protected 和 public 类及成员。
  -package 只显示包、protected 和 public 类及成员。这是缺省设置。
  -private 显示所有类和成员。
  -s 输出内部类型签名。
  -c 输出类中各方法的未解析的代码,即构成 Java 字节码的指令。
  -verbose 输出堆栈大小、各方法的 locals 及 args 数,以及class文件的编译版本
  -classpath[路径] 指定 javap 用来查找类的路径。如果设置了该选项,则它将覆盖缺省值或 CLASSPATH 环境变量。目录用冒号分隔。
  -bootclasspath[路径] 指定加载自举类所用的路径。缺省情况下,自举类是实现核心 Java 平台的类,位于 jrelib下面。
  -extdirs[dirs] 覆盖搜索安装方式扩展的位置。扩展的缺省位置是 jrelibext。

你可能感兴趣的:(JAVA)