字节码
字节码简介
- java源码经过编译生成之后二进制称为字节码文件,不一定是,也可能是网络传过来符合字节码规范的二进制流
- JVM通过字节码保证平台无关性
- Java并不是唯一生成class文件的语言
- Class是结构紧凑的二进制流,格式固定,要求严谨
字节码组成结构
- 魔数:区分文件类型的依据,字节码文件的前四个字节为魔数(字节码文件魔数为CA FE BA BE)
文件版本:
- 5-6字节为次要版本,7-8为主要版本号 Java 8=52.0
- 字节码版本高于JVM版本,会产生UnsupportedClassVersion
- | JDK版本号 | Class版本号 | 16进制 |
| --------- | ----------- | ----------- |
| 1.1 | 45.0 | 00 00 00 2D |
| 1.2 | 46.0 | 00 00 00 2E |
| 1.3 | 47.0 | 00 00 00 2F |
| 1.4 | 48.0 | 00 00 00 30 |
| 1.5 | 49.0 | 00 00 00 31 |
| 1.6 | 50.0 | 00 00 00 32 |
| 1.7 | 51.0 | 00 00 00 33 |
| 1.8 | 52.0 | 00 00 00 34 |
| 9 | 53.0 | 00 00 00 35 |
| 10 | 54.0 | 00 00 00 36 |
| 11 | 55.0 | 00 00 00 37 |
| 12 | 56.0 | 00 00 00 38 |
| 13 | 57.0 | 00 00 00 39 |
| 14 | 58.0 | 00 00 00 3a |
| 15 | 59.0 | 00 00 00 3b |
| 16 | 60.0 | 00 00 00 3c |
| 17 | 61.0 | 00 00 00 3d |
| 18 | 62.0 | 00 00 00 3e |常量池
字面量
- 字符串
- final修饰
符号引用
- 类和接口的全限定名
- 字段名称与描述符
- 方法名称与描述符
- 常量池类型数据表
类索引
- 标识父类以及实现了哪些接口
访问标志
- AccessFlag访问表
字段表
- 哪些字段,以及类型
方法表
- 方法名、方法参数、返回值
- 属性表
字节码指令
字节码指令将源码编译时由编译器生成保存在Method描述中的,与平台无关,运行时,jvm读取后翻译各平台底层指令,总数不超过256个
例子:
invokevirtual #8 // cp_info#8:java/lang/StringBuilder.append
执行StringBuilder对象的append方法
new #6 // cp_info#6:<java/langStringBuilder>
实例化新的StringBuilder对象并将实例化的对象保存至堆中
字节码指令分类
- 加载与存储指令
- 运算指令
- 类型转换指令
- 对象创建与访问指令
- 操作数栈管理
- 控制转移指令
- 方法调用与返回指令
- 同步指令指令
- 异常处理指令
类加载子系统
类加载执行过程
类加载子系统是字节码文件到数据区经历的过程
类加载子系统负责从文件或者网络中加载Class字节流读取符合jvm规范的字节码信息,并在存储到方法区中
类加载过程
加载阶段
读取字节码二进制流
解析字节码二进制流的静态数据转换为运行时JVM方法区数据
生成类的实例对象,放入堆中,作为方法区
若运行时需要到A类,但是不存在A类时,A类会被类加载器加载,并将A的Class实例放到堆中,将A类的字段、方法描述放在方法区中,同时A被加载的时候A的父类同时被加载
Class实例被创建的时机:
new实例化的时候
- A a = new A();
反射
- Class clzA = Class.forName("com.mc10010.A")
- 子类加载时父类同时加载
- jvm启动时,包含main方法的主类
- 1.7的动态类型语言支持
链接阶段
验证阶段
确保字节码符合虚拟机规范
文件格式校验
- 是否以CAFEBABE开头
- 版本号是否匹配
元数据匹配、语义分析
- 是否有父类
- 是否继承final修饰的类
- 其他有悖Java规则的错误
字节码验证
- 类型转换是否有效
- 是否可以执行到return
符号引用
- ClassNotFoundException
- NoSuchMethodError
- 全部都是基于字节码对应的二进制流进行的,基于文件本身的处理
准备阶段
为static赋予初始值,这里只赋值初始值,而不是赋值!!!
- 例如public static int a = 100; 在这个阶段int只赋值为0
解析阶段(核心所在)
- 将字节码静态字面关联转换成JVM内存中的动态指针关联
- 其实就是把字符串关联改成指针关联
此处评论已关闭