什么是类加载,又有哪些类加载器你真的了解吗?
Posted 你这家伙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是类加载,又有哪些类加载器你真的了解吗?相关的知识,希望对你有一定的参考价值。
类加载
1.1.什么是类加载?
就是.java代码通过javac编译生成.class文件(文件是保存在磁盘上的),如果想要JVM使用这个类,那就需要将这个类加载到内存中,这个过程成为“类加载”。
三个步骤:
- **1. 加载(loading):**读取.class文件,按照格式来进行解析(.class文件是有固定的格式,javac生成的时候就会按照这个格式来进行组织,JVM加载的时候也会按照这个格式来进行解析)
- **2. 连接(linking):**一个类可能会依赖其他类,如果想要使用这个类,需要将这个类依赖的类也需要加载
- **3. 初始化:**创建类对象,初始化该类的静态成员,并且执行静态代码块中的内容
注意:
类型的加载,连接,初始化都是在程序运行期间完成的,(类型:指的是定义的类,接口或者枚举成为类型而不涉及对象,在类加载的过程中,就是一个创建对象之前的一些信息)
示例:
class A{
public A(){
System.out.println("A的构造");
}
{
System.out.println("A的构造块");
}
static {
System.out.println("A的static块");
}
}
class B extends A{
public B(){
System.out.println("B的构造");
}
{
System.out.println("B的构造块");
}
static {
System.out.println("B的static块");
}
}
public class Test extends B{
public static void main(String[] args) {
System.out.println("开始");
new B();
new B();
System.out.println("结束");
}
}
此时你先可以不用看下面,看看你自己得到的答案是什么,看你是否对这个已经掌握?
输出结果为
对此知道的人就是知道了,不知道的你可能还在疑惑当中,别急,听我细细道来
示例修改:
如果此时Test不继承B,那么输出结果又是如何呢?上面回答错误的老铁给个机会,这次在思考看看有没有进步嘞
输出结果:
结果分析:
1.2.Java中有哪些类加载器?
就是JVM里已经实现好了的类,通过这些特殊的类来具体执行类加载的过程
默认主要有三个类加载器(用户也可以自定新的类加载器):
- BootstrapClassLoader:专门加载java标准库中的类
- ExternsionClassLoader:加载一些特殊的类
- ApplicationClassLoader:加载用户自己写的类
-
BootstrapClassLoader加载器
那么标准库的类都在哪里呢?
如果类在jdk1.8 / jre / lib / rt.jar(可以用压缩包打开),这个文件下,那么就可以使用BootstrapClassLoader加载器来进行加载
-
ExternsionClassLoader加载器
因为他是加载特殊的类,所以这里就找一个特殊的类来示例
如果类在jdk1.8 / jre / lib / ext目录下,那么就需要通过ExternsionClassLoader加载器来加载
- ApplicationClassLoader加载器
如果类在CLASS_PATH环境变量,或者java -cp指定的目录,或者在当前的目录中,就使用ApplicationClassLoader加载器进行加载
1.3.什么是“双亲委派模型”/“双亲委派原则”?
上面所提到的类加载器之间,其实具有父子关系(但是不是通过类的继承)
- BootstrapClassLoader 是 ExternsionClassLoader 的父亲
- ExternsionClassLoader 是 ApplicationClassLoader 的父亲
其实在进行类加载的时候,有一个约定好的顺序
以加载String为例
- JVM需要加载类的时候,无论是这个类是什么样的,统一都从Application开始执行
- 把类名(java.lang.String)告诉给Application ,Application自身不会真的取进行加载,而是先去找他的父亲Externsion
- 当Externsion 拿到这个类名之后同样也不会真的取执行,而是在把任务交给他的父亲Bootstrap
- Bootstrap 拿到这个类名的时候,此时它上面没有父亲了,那就只能亲自己加载
- 由于String类就在rt.jar 里,此时Bootstrap就加载成功
6.此时的Externsion 和Application就不需要在进行其他工作了
总结:遇到类名,先找爸爸,爸爸搞不定,再自己进行加载,如果到最后都找不到就会抛出一个ClassNotFoundExceptin的异常
1.4.自己创建的类加载器是否也要遵循双亲委派模型?是否可以违背?
可以违背,不一定非要遵守,只是标准库中的三个类加载器遵循双亲委派模型
(比如tomcat中的类加载器就没有遵守,webapps 目录中要放很多的.class文件,tomato在执行的时候,实现了自己的类加载器,专门负责从指定的webapps目录中加载对应的类,那么此处就不存在“传递给父类加载器”)
常见面试题
1.什么时候会触发某个类的加载?
答:当使用到一个类的时候,并且该类不在内存中,这个时候就需要加载。那么使用到一个类的时候具体是什么时候呢?
- 构造类的实例(new实例的时候)
- 使用该类的静态属性/方法
- 使用子类的时候,也会触发父类的加载。
可以综合上面的例题进行分析
以上是关于什么是类加载,又有哪些类加载器你真的了解吗?的主要内容,如果未能解决你的问题,请参考以下文章