1 java字节码
1.1 什么是字节码
java bytecode由单字节(byte)的指令组成,最多支持256个操作码,只使用了200左右的操作码,还有一些操作码保留给调试操作。
根据指令的性质,分为四大类:
1.栈操作指令,包括与局部变量交互的指令
2.程序流程控制指令
3.对象操作指令,包括方法调用指令
4.算术运算以及类型转换指令
package demo.jvm0104;
class HelloByteCode {
public static void main(String[] args) {
HelloByteCode obj = new HelloByteCode();
}
}
编译
javac demo/jvm0104/HelloByteCode.java
查看字节码
$ javap -c demo.jvm0104.HelloByteCode
Compiled from "HelloByteCode.java"
class demo.jvm0104.HelloByteCode {
demo.jvm0104.HelloByteCode();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class demo/jvm0104/HelloByteCode
3: dup
4: invokespecial #3 // Method "<init>":()V
7: astore_1
8: return
}
查看字节码详细信息
javap -c -verbose demo.jvm0104.HelloByteCode
$ javap -c -verbose demo.jvm0104.HelloByteCode
Classfile /D:/liyuan-gitee/geekbamg-java-my-vscode/myproj/week01/demo/jvm0104/HelloByteCode.class
Last modified 2024-7-30; size 301 bytes
MD5 checksum 07e48d4e5c691a90c0605b12408b37f1
Compiled from "HelloByteCode.java"
class demo.jvm0104.HelloByteCode
minor version: 0
major version: 52
flags: ACC_SUPER
Constant pool:
#1 = Methodref #4.#13 // java/lang/Object."<init>":()V
#2 = Class #14 // demo/jvm0104/HelloByteCode
#3 = Methodref #2.#13 // demo/jvm0104/HelloByteCode."<init>":()V
#4 = Class #15 // java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Utf8 LineNumberTable
#9 = Utf8 main
#10 = Utf8 ([Ljava/lang/String;)V
#11 = Utf8 SourceFile
#12 = Utf8 HelloByteCode.java
#13 = NameAndType #5:#6 // "<init>":()V
#14 = Utf8 demo/jvm0104/HelloByteCode
#15 = Utf8 java/lang/Object
{
demo.jvm0104.HelloByteCode();
descriptor: ()V
flags:
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: new #2 // class demo/jvm0104/HelloByteCode
3: dup
4: invokespecial #3 // Method "<init>":()V
7: astore_1
8: return
LineNumberTable:
line 5: 0
line 6: 8
}
SourceFile: "HelloByteCode.java"
1.2 方法调用的指令
方法调用的指令:
invokestatic,顾名思义,这个指令用于调用某个类的静态方法,这是方法调用指令中最快的一个。
invokespecial, 用来调用构造函数,但也可以用于调用同一个类中的 private 方法, 以及可见的超类方法。
invokevirtual,如果是具体类型的目标对象,invokevirtual 用于调用公共,受保护和package 级的私有方法。
invokeinterface,当通过接口引用来调用方法时,将会编译为 invokeinterface 指令。
invokedynamic,JDK7 新增加的指令,是实现“动态类型语言”(Dynamically Typed Language)支持而进行的升级改进,同时也是 JDK8 以后支持 lambda 表达式的实现基础。
2 jvm类加载器
2.1 类的生命周期
- 加载(Loading):找 Class 文件
- 验证(Verification):验证格式、依赖
- 准备(Preparation):静态字段、方法表
- 解析(Resolution):符号解析为引用
- 初始化(Initialization):构造器、静态变量赋值、静态代码块
- 使用(Using)
- 卸载(Unloading)
2.2 类的加载时机
- 当虚拟机启动时,初始化用户指定的主类,就是启动执行的 main 方法所在的类;
- 当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类,就是 new一个类的时候要初始化;
- 当遇到调用静态方法的指令时,初始化该静态方法所在的类;
- 当遇到访问静态字段的指令时,初始化该静态字段所在的类;
- 子类的初始化会触发父类的初始化;
- 如果一个接口定义了 default 方法,那么直接实现或