一、Java如何运行
- Java代码文件会编译成可运行的.class字节码文件;
- JVM在运行.class文件时需要依赖的.class文件或者jar包里面的某个.class,则通过类加载器去加载到内存;
- JVM会基于自己的字节码引擎,来执行加载到内存里已写好的类
二、类加载到使用的过程
加载->验证->准备->解析->初始化->使用->卸载
- 加载:JVM会将需要代码运行时需要的类加载到内存中(通过类加载器);
- 验证:根据Java虚拟机规范,校验加载的.class文件内容是否符合指定的规范(例如字节码文件被篡改);
- 准备:主要是分配内存空间;
如果有
public static int count;
类似这样的变量 【类变量】,分配内存空间的同时初始化一个默认值
- 解析:实际上是将符号引用替换成直接引用
- 核心阶段初始化: 在准备阶段,对于count这个静态变量会默认初始化0,但是赋值操作是在初始化阶段,如下的Configuration.getInt("studnet.count");赋值操作;另外,静态代码块的执行也是在这个阶段。
public class LoadStudent {
public static int count = Configuration.getInt("studnet.count");
public static Map<String, Student> students;
static {
initStudents();
}
public static void initStudents() {
this.students = new HashMap<String, Student>();
}
}
复制代码
类初始化的时机:当类被使用的到的时候,如:LoadStudent load = new LoadStudent(); 如果初始化一个类的时候,发现该类有父类,必须先初始化他的父类
实现上述初始化类的过程,需要由类加载器来完成,Java中的类加载器有:
(1)启动类加载器Bootstrap ClassLoader,启动JVM,会加载jdk目录下的lib目录下的核心类库
(2)拓展类加载器Extension ClassLoader,启动JVM,会加载jdk目录下的lib/ext目录下的拓展类库
(3)应用程序类加载器Application ClassLoader,加载classpath环境变量哦指定的路径中的类,可以理解成加载你写到的Java代码到内存
(4)自定义类加载器,除了上述几种类加载器之外,还可以自定义类加载器
他们亲子层结构关系如下图:
双亲委派机制:简单来说,子类加载器先会找父类加载器去加载类,找不到的话再由子类去加载