Class文件是个啥?

Class文件是个啥?

为啥需要编译?
大家都知道Java是一门静态语言,java文件会通过编译生成class文件,运行时jvm直接加载运行class文件。jvm面向字节码而不是机器码,个人理解有以下几个好处:

  1. java虚拟机在机器和java程序之间抽象出来一个统一的接口,使得编译出来的同一份字节码文件可以在不同的平台上运行;
  2. 提前把源码的校验、编译等耗时操作放到编译过程,加快程序执行效率;
  3. java可以认为是一种半解释性语言(jvm通过实时解释class文件生成机器码运行),即拥有解释性语言可移植的特性,也兼顾了执行效率(对1,2点的总结);
  4. 编译期优化,编译过程可以加入对源码的优化,提高程序执行效率;
  5. jvm是面向字节码的,因此当有新的java语法糖出现时,只需要在编译器层面进行适配生成对应的字节码即可;
  6. 编译后的文件只保留关键信息,体积更小,方便传输;

Class文件是个啥?_第1张图片

  1. 词法分析
    输入:java源代码
    输出:Token流
    过程:根据java定义的关键字把源代码片段切分为一句句的执行命令(Token,字符串为单位),并为Token打上标记。词法分析器通常不会关心标记之间的关系(属于语法分析的范畴),举例来说:词法分析器能够将括号识别为标记,但并不保证括号是否匹配。
  2. 语法分析
    输入:Token流
    输出:语法树
    过程:
    a. 检查Token是否存在语法错误,比如 if(a=b){…},在语法分析阶段会报错。
    b. 生成语法树
    此阶段会对单个token进行语法分析,不能保证token的上下文语义信息是否正确。
  3. 注解语义分析
    输入:语法树
    输出:注解语法树
    过程:
    a. 对语法树进行语义检查。比如定义了常量final int a=0;若后面对a进行赋值,则会报错;
    b. 使用不同的注解解析器对语法树进行修改,比如对java语法糖的支持,把foreache关键字转化为for循环基础操作
    c. 去除无用的代码
    d. 对代码进行重排优化等(c,d可以理解为b的具体操作)
  4. 生成代码
    输入:注解语法树
    输出:.class字节码文件
    过程:根据注解语法树,和字节码文件的规则生成字节码文件。
    字节码文件是什么?
    编译后的字节码文件格式主要分为两部分:常量池和方法字节码。
      常量池记录的是代码出现过的字面量(文本字符串、八种基本类型的值、被声明为final的常量等)以及符号引用(类和方法的全限定名、字段的名称和描述符、方法的名称和描述符);
    方法字节码中放的是各个方法的字节码(依赖操作数栈和局部变量表,由JVM解释执行)
    文件结构:
    Class文件是个啥?_第2张图片
    下面根据一个简单的例子分析一下:
public class HelloWorld {
    public void main(String args[]){
        System.out.println("hello world");
    }
}

先看一下反编译结果:

public class HelloWorld {
    public HelloWorld() {
    }

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

再看一下字节码文件:

CA FE BA BE 00 00 00 34 00 22 0A 00 06 00 14 09 00 15 00 16 08 00 17 0A 00 18 00 19 07 00 1A 07
 00 1B 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E
 75 6D 62 65 72 54 61 62 6C 65 01 00 12 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65 01
 00 04 74 68 69 73 01 00 0C 4C 48 65 6C 6C 6F 57 6F 72 6C 64 3B 01 00 04 6D 61 69 6E 01 00 16 28
 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 01 00 04 61 72 67 73 01 00 13 5B
 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 01 00 0A 53 6F 75 72 63 65 46 69 6C 65 01
 00 0F 48 65 6C 6C 6F 57 6F 72 6C 64 2E 6A 61 76 61 0C 00 07 00 08 07 00 1C 0C 00 1D 00 1E 01 00
 0B 68 65 6C 6C 6F 20 77 6F 72 6C 64 07 00 1F 0C 00 20 00 21 01 00 0A 48 65 6C 6C 6F 57 6F 72 6C
 64 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 10 6A 61 76 61 2F 6C 61 6E 67
 2F 53 79 73 74 65 6D 01 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74
 72 65 61 6D 3B 01 00 13 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 01 00 07 70 72
 69 6E 74 6C 6E 01 00 15 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 00 21 00
 05 00 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00 2F 00 01 00 01 00 00 00 05 2A
 B7 00 01 B1 00 00 00 02 00 0A 00 00 00 06 00 01 00 00 00 01 00 0B 00 00 00 0C 00 01 00 00 00 05
 00 0C 00 0D 00 00 00 01 00 0E 00 0F 00 01 00 09 00 00 00 41 00 02 00 02 00 00 00 09 B2 00 02 12
 03 B6 00 04 B1 00 00 00 02 00 0A 00 00 00 0A 00 02 00 00 00 03 00 08 00 04 00 0B 00 00 00 16 00
 02 00 00 00 09 00 0C 00 0D 00 00 00 00 00 09 00 10 00 11 00 01 00 01 00 12 00 00 00 02 00 13

下面我们就按照class文件的设计结构人肉翻译一波:

名称 长度 字节码 翻译
magic(魔数) 4byte CA FE BA BE CA FE BA BE
magic(魔数) 4byte CA FE BA BE CA FE BA BE
minor_version(JDK次版本号) 2byte 00 00 0
major_version(JDK主版本号) 2byte 00 34 52,代表jdk1.8
constant_pool_count(常量池数量) 2byte 00 22 34, 常量个数
constan_pool(常量表) constant_pool_count - 1 * 常量长度 0A 00 06 00 14 09 00 15 00 16 08 00 17 0A 00 18 00 19 07 00 1A 07 00 1B 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 01 00 12 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65 01 00 04 74 68 69 73 01 00 0C 4C 48 65 6C 6C 6F 57 6F 72 6C 64 3B 01 00 04 6D 61 69 6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 01 00 04 61 72 67 73 01 00 13 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 01 00 0A 53 6F 75 72 63 65 46 69 6C 65 01 00 0F 48 65 6C 6C 6F 57 6F 72 6C 64 2E 6A 61 76 61 0C 00 07 00 08 07 00 1C 0C 00 1D 00 1E 01 00 0B 68 65 6C 6C 6F 20 77 6F 72 6C 64 07 00 1F 0C 00 20 00 21 01 00 0A 48 65 6C 6C 6F 57 6F 72 6C 64 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D 01 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B 01 00 13 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 01 00 07 70 72 69 6E 74 6C 6E 01 00 15 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 每个tag对应的不同类型的常量,长度不一样,可以参考tag类型表一起看。比如:0A 00 06 00 14,0A为tag=10,即CONSTANT_Methodref_info,描述方法的信息,内容为4字节,分别为2字节方法所属的类名常量class_name_info_index=6,和方法名称和返回类型的索引NameAndType_info_index=20,而此常量的索引为1;
access_flags(访问标志) 2byte 00 21 表示访问权限和类型,可以参考access_flag表;0021=0001
this_class(本类的描述符索引) 2byte 00 05 对应07 00 1A,代表类型为class,索引为26,26=Helloworld
super_class(父类) 2byte 00 06 对应 07 00 1B,代表类型为class,索引为27,27=java/lang/Object
interface_count 2byte 00 00 没有实现接口
interface 2byte*interface_count
filed_count 2byte 00 00 没有属性
fileds(属性) filed_info*filed_count
method_count 2byte 00 02 2个方法
method_info method_info*method_count 00 01 00 07 00 08 00 01 00 09 00 00 00 2F 00 01"public #7 #8 1attr code xxxx "

tag类型表:
Class文件是个啥?_第3张图片
access_flag表:

标志值 标志含义 类型 针对的对像
ACC_PUBLIC 0x0001 public类型 所有类型
ACC_FINAL 0x0010 final类型
ACC_SUPER 0x0020 使用新的invokespecial语义 类和接口
ACC_INTERFACE 0x0200 接口类型 接口
ACC_ABSTRACT 0x0400 抽象类型 类和接口
ACC_SYNTHETIC 0x1000 该类不由用户代码生成 所有类型
ACC_ANNOTATION 0x2000 注解类型 注解
ACC_ENUM 0x4000 枚举类型 枚举
ACC_PRIVATE 0X0002 private类型 所有类型

filed_info结构:

类型 名称 数量
u2 access_flags 1
u2 name_index 1
u2 description_index 1
u2 attributes_count 1
Attribute_info attributes attributes_count

其中的access_flags与类中的access_flags非常类似,是表示数据类型的修饰符,如public、static、volatile等。后面的name_index和descriptor_index都是对常量池的引用,分别代表字段的简单名称及字段和方法的描述符,之后紧跟着一个属性表集合用于存储一些额外的信息。
method_info表结构,跟field_info结构相似:

类型 名称 数量
u2 access_flags 1
u2 name_index 1
u2 description_index 1
u2 attributes_count 1
Attribute_info attributes attributes_count

code属性:
Class文件是个啥?_第4张图片
exception:
Class文件是个啥?_第5张图片
以上就是class文件的"翻译"过程,可以通过命令javap来解析class来对照着看:
常量池:
Class文件是个啥?_第6张图片
方法区:
Class文件是个啥?_第7张图片
参考资料:
https://blog.csdn.net/u014629433/article/details/51626686
https://blog.csdn.net/tyyj90/article/details/78472986
https://www.jianshu.com/p/704812a73ee2

你可能感兴趣的:(java,java,jvm)