加载class 文件到内存
- 加载(三件事)
1.1 这个文件在哪儿?它是jar 还是class 文件?
java TestClass
java -jar
1.2 静态存储结构转化方法区的运行时数据结构
jvm 运行时数据区
方法区:存放的是常量池和方法,
堆(heap):存放的是对象
1.3 java堆里面生成一个Class对象(相当于一个句柄),去访问方法区。
-
验证
2.1 验证Class文件的标识:魔数Magic Number
2.2 验证Class文件的版本号
2.3 验证常量池(常量类型,常量类型数据结构是否正确、UTF8是否符合标准)
2.4 Class文件的每个部分(字段表、方法表等)
2.5 元数据验证(final验证、父类验证、继承验证)
2.6 字节码验证(指令验证)
2.7 符号引用验证(通过符号引用是否能找到字段、方法、类) -
准备
为类变量分配内存并且设置类变量的初始化阶段,只对static类变量进行内存分配。
static int n=2; //初始化值是0,而不是2。因为这个时候还没执行任何java 方法.需要clinit去初始化
static final int n=2;// 对应到常量池 ConstantValue,在准备阶段n必须被赋值为2。直接使用init初始化
类变量:一般称为静态变量
实例变量:当对象被实例化的时候,实例变量就跟着确定。随着对象的销毁而销毁。
- 解析
对符号引用进行解析:把符号引用指向直接引用
直接引用:指向目标的指针或者偏移量。
符号引用=>直接引用。
主要涉及:类、接口、字段、方法(接口、类)等。
CONSTANT_Class_info
CONSTANT_Fieldref_info
CONSTANT_Methodref_info
CONSTANT_InterfaceMethodref_info
CONSTANT_MethodType_info
CONSTANT_MethodHandler_info (方法=>vtable=>itable)
CONSTANT_invokeDynamic_info
匹配规则:简单名字(方法名)+描述符(参数+返回类型)同时满足,如 public String test(),简单名字就是test,描述符就是 ()String
4.1 字段的解析
在本类里面去找有没有匹配的字段=>如果类有接口,往上层接口找匹配的字段==>搜索父类
eg:
class A extends B implements C,D{
private String str;//字段
}
解析字段的顺序:A(分类)=>C,D(父接口)=>B(父类)=>Object(根类)
如果找到了,但是没有权限:java.lang.IllegalAccessError
如果失败(没找到):java.lang.NoSuchFieldError
4.2 类方法的解析
在本类里面去找有没有匹配的方法==>父类去找匹配的方法=>接口列表里面去找匹配方法(代表本类是一个抽象类,查找结束,抛出java.lang.AbstractMethodError异常)
如果找到了,但是没有权限:java.lang.IllegalAccessError
如果失败(没找到):java.lang.NoSuchFieldError
eg:
class A extends B implements C,D{
private void inc();//字段
}
4.3 接口方法的解析
在本类里面去找有没有匹配的方法=>父类接口中递归查找
如果失败(没找到):java.lang.NoSuchMethodError
5. 初始化
Class A{
static int i=2;
static {
System.out.println("");
}
int n;
}