面试题:JVM类加载机制 -- 双亲委派机制
前置知识
JVM类加载机制主要有如下三种方式
- 全盘负责:指当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责加载,除非显示使用另一个类加载器来载入
- 双亲委派:指先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该Class
- 缓存机制:当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为什么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因
JVM自带的类加载器
- 启动类加载器(Boostrap ClassLoader):负责加载Java核心类库。出于安全考虑,引导类加载器只加载器包名为 java, javax , sun等开头的类
- 使用C/C++语言实现,嵌套在JVM内部。不继承于
java.lang.ClassLoader
,没有父类加载器 - 负责加载扩展类加载器和应用类加载器,并为它们指定父类加载器
- 使用C/C++语言实现,嵌套在JVM内部。不继承于
- 扩展类加载器(Extension ClassLoader):。从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK系统安装目录的jre/lib/ext子目录(扩展目录)下加载类库。
- Java语言编写,由
sun.misc.Launcher$ExtClassLoader
实现,父类加载器为 null - 派生于
java.lang.ClassLoader
类
- Java语言编写,由
- 应用类加载器(Application ClassLoader):负责加载开发者自定义的类。该类加载器是程序中默认的类加载器
-
JVM类加载机制 -- 双亲委派机制
双亲委派机制:ClassNotFoundException
双亲委派优点
- 可以避免开发者自定义的类动态的替换Java的核心类
- 如java.lang.String。java核心API中定义类型不能被随意替换,假设通过网络传递一个名为
java.lang.Integer
的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer
,而直接返回已加载过的Integer.class
,这样便可以防止核心API库被随意篡改
- 如java.lang.String。java核心API中定义类型不能被随意替换,假设通过网络传递一个名为
- 可以避免全限定命名的类重复加载(使用findLoadClass()方法判断当前类是否已加载)
- Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父类加载器已经加载了该类时,就没有必要子加载器再加载一次
Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行