目录
在面试中经常会遇到这样一道面试题“你知道类加载过程吗?什么是双亲委派”;下面我们就针对这个问题展开,看看类加载过程,以及双亲委派机制
类加载过程
类加载过程有三个阶段:加载、链接以初始化;其中链接阶段有可以细分为:验证、准备和解析。如图所示:
加载
- 通过类的全限定名获取定义这个类的字节码,并载入方法区;创建类的Class对象
- 如果类的父类没有加载需要先加载父类
链接
验证
验证阶段主要工作就是验证类是否符合JVM虚拟机规范,是否合法以及安全性检查
- 文件格式验证,比如验证魔数“0xCAFEBABE”以及虚拟机主副版本号等
- 元数据验证,这是对字节码语义分析保证语义也是符合虚拟机规范
- 字节码验证,主要是验证字节码控制流程验证,保证字节码不会出现危害虚拟机的操作
- 符号引用验证 ,主要验证符号引用的类是否存在,是否可以被访问
准备
准备阶段为类的静态变量分配空间并设置初始值,这里的初始值是指类型的初始值;比如如下语句在准备阶段a的值是0而不是1,那么什么时候才会为1呢?这个要等到初始化阶段才会赋值。
public static int a=1;
那么是不是所有的属性都是这样呢?如下一条语句在准备阶段就是1
public static final int a=1;
解析
解析阶段主要工作就是将常量池中的符号引用转化为直接引用
初始化
初始化是类加载过程的最后一步,而这一步才是真正开始执行JAVA代码。初始化阶段是执行类的构造器<clinit>方法的过程。类构造器与类的初始化方法是不同的。
public class ClinitTest {
private static String property = "test";
static {
System.out.println("static block");
}
private int a = 1;
public static void main(String[] args) {
ClinitTest clinitTest = new ClinitTest();
clinitTest.print();
}
private void print() {
System.out.println(a);
}
}
上面这段代码编译后的字节码如下:
Compiled from "ClinitTest.java"
public class com.dora.jvm.ClinitTest
minor version: 0
major version: 61
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #8 // com/dora/jvm/ClinitTest
super_class: #2 // java/lang/Object
interfaces: 0, fields: 2, methods: 4, attributes: 1
Constant pool:
#1 = Methodref #2.#3 // java/lang/Object."<init>":()V
#2 = Class #4 // java/lang/Object
#3 = NameAndType #5:#6 // "<init>":()V
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Fieldref #8.#9 // com/dora/jvm/ClinitTest.a:I
#8 = Class #10 // com/dora/jvm/ClinitTest