JVM类加载器及类加载机制详解
类加载器种类
启动类加载器:
- 负责加载JRE的核心类库,如jre包下的rt.jar、charset.jar等。拓展类加载器:
扩展类加载器:
- 负责加载jre扩展目录ext中的jar包。
系统类加载器:
- 用户自定义加载器:
用户自定义加载器:
- 负责加载用户自定义路径下的类包。
类加载机制
全盘负责委托机制:
- 一个ClassLoader加载一个类是,除非显示的引用另一个ClassLoader,该类所依赖和引用的类都由该ClassLoader载入。
双亲委派模式:
- 类加载的时候先委托父类加载器寻找目标类,如果找不到目标类才在的路径中查找并加载目标类。
双亲委派模式如下图:
双亲委派模式优点:
- 沙箱安全机制:防止核心API库被恶意篡改。
- 避免类重复加载:当父类加载了该类时,子类就不会再次加载该类。
代码演示:
package java.lang;
/**
* @Author xiaolinzi
* @Date 2020/2/26 2:24 下午
* @Email xiaolinzi95_27@163.com
*/
public class String {
public static void main(String[] args) {
System.out.println("自定义String类是否可以被加载");
}
}
我们自己写一个java.lang.String类,然后运行其main方法看是否可以加载并运行该类。我们运行自定义String类的main方法。然后报以下错误:
这就意味着我们自己定义的String类并没有被加载,他是使用启动类加载器加载的jdk中rt包下的java.lang.String类,但是该包下的类并没有main方法,所以报错。
那如何证明启动的时候,类加载器加载的是rt包下的java.lang.String而不是我们自定义的String呢?可以在运行代码的时候在vm启动参数加上参数 -verbose:class
如下图:
类加载过程:
Jvm对class类文件是按需加载(运行时动态加载),非一次性加载,如以下示例:
代码示例
/**
* @author :zhangshilin
* @date :2020-2-26 15:39
* @Email xiaolinzi95_27@163.com
*/
public class ClassLoad {
static {
System.out.println("*************static code************");
}
public static void main(String[] args){
new A();
System.out.println("*************load test************");
new B();
}
}
class A{
public A(){
System.out.println("*************initial A************");
}
}
class B{
public B(){
System.out.println("*************initial B************");
}
}
加上在vm启动参数中加上-verbose:class看控制台日志:
可以看出并A,B并不是一开始就加载的,而运行时动态加载。
还没有评论,来说两句吧...