1、类加载子系统的模型图
2、类加载子系统分为三个阶段:
- 1、加载阶段:
加载阶段有引导类/启动类加载器、扩展类加载器、系统类/应用程序类加载器: - 2、链接阶段
链接阶段分为验证、准备、解析 - 3、初始化阶段
3、加载阶段介绍:
加载阶段除了引导类加载器,扩展类加载器,系统类加载器外,还有自定义类加载器。
3.1、引导类加载器,它不是有Java写的,它通过C/C++语言写的。它不可以通过java获取到,
3.2、扩展类加载器是通过Java语言编写的,它可以通过系统类加载器获取到。
3.3、系统类加载器是Java语言写的,它可以通过getClassLoader()方法获取。同时我们经常写的类的加载器也继承自系统类加载器。
获取加载器代码:获取加载器的代码
3.4、自定义加载器,开发人员可以继承抽象类java.lang.Class类的方式,实现自己的类加载器,以满足一些特殊的需求。在JDK1.2之后,不在需要用户自己覆盖loadClass()方法,而是建议把自定义类加载器逻辑写在findClass()方法中,而findClass(),一般配合defineClass方法使用。
自定义类创建的代码:自定义类加载代码
3.5、获取类的加载器:
第一种:获取当前类的ClassLoader。使用clazz.getClassLoader()
代码:获取ClassLoader
第二种方法:获取当前线程上下文的ClassLoader。使用Thread.currentThread().getContextClassLoader()
代码:获取ClassLoader
第三种:获取系统的ClassLoader。使用ClassLoader.getSystemClassLoader()
代码:获取ClassLoader
第四种:获取调用者的ClassLoader。使用DriverManager.getCallerClassLoader()
4、链接阶段的介绍
4.1、验证:验证阶段在整个Class加载过程中占很大的比例。它放置代码的恶意攻击。
4.2、准备:
变量在准备时就进行赋值为0;
如果被final修饰的static,因为final在编译的时候就会被分配,准备阶段会显示初始化;
这里不会为实例变量分配初始化,类变量会分配到方法区,而实例变量是随着对象一起分配到Java堆中
4.3、解析:不清楚
5、初始化阶段
5.1、变量赋值是在初始化;
5.2、初始化阶段就是执行类构造器方法<clinit>()
的过程;
5.3、此方法不需要定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来的。如果不是static,就不会有<clinit>()
;
5.4、<clinit>()
不同于类构造器(关联:构造器是虚拟机视角下的<init>
)
5.5、若该类具有父类,JVM会保证子类的<clinit>()
执行前,父类的<clinit>()
已经执行完毕。
5.4、虚拟机必须保证一个类的<clinit>()
方法在多线程下被同步加锁。
6、关于双亲委派机制:
6.1、Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类是才会将它的class文件加载到内存生成calss对象。而且加载某个类的class文件时,即把请求交由父类处理,它是一种认为委派模式。
6.2、工作原理:
如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行。
如果父类加载器还存在其父类加载器,则进一步向上委托,一次递归,请求最终将到达顶层的启动类加载器。
如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器复发完成此加载任务,自家在其才会城市自己去加载,这就是双亲委派模式。
6.3、优势:
避免类的重复加载
保护程序安全,放置核心API被随意篡改:如:
自定义类:java.lang.String
自定义类:java.lang.ShkStart
代码:
6.4、沙箱安全机制:
自定义String类,但是在加载自定义String类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件(rt.jar中的java\lang\String.class),报错信息说没有main方法,就是因为加载的是rt.jar包中的String类。这样可以保证对java核心代码的保护,这就是沙箱安全机制。
package com.cad.JvmTest.lang;
// 下列代码无法使用。这就是双亲委派机会的好处。
public class String {
static {
System.out.println("我是自定义的String的静态代码块");
}
public static void main(String[] args) {
System.out.println("hello world");
}
}