类加载流程
这里的引导类加载器是值BootStrapClassLoader, 其他类加载器包括ExtClassLoader ApplicationClassLoader
JVM默认提供了三种类加载器,它们负责加载不同的类:
我们自己写的类,都是由应用类加载器来加载的;
package com.lchtest;
import sun.net.spi.nameservice.dns.DNSNameService;
public class Car {
public static void main(String[] args) {
Car car1 = new Car();
Car car2 = new Car();
System.out.println(car1);
System.out.println(car2);
System.out.println(car1.hashCode());
System.out.println(car2.hashCode());
// Class 类是模板,对象时具体的
Class<? extends Car> aClass1 = car1.getClass();
Class<? extends Car> aClass2 = car2.getClass();
System.out.println(aClass1);
System.out.println(aClass2);
System.out.println(aClass1.hashCode());
System.out.println(aClass2.hashCode());
System.out.println(aClass1.getClassLoader()); // 应用程序类加载器 sun.misc.Launcher$AppClassLoader@18b4aac2
System.out.println(aClass1.getClassLoader().getParent()); // 扩展类加载器 sun.misc.Launcher$ExtClassLoader@1540e19d
System.out.println(aClass1.getClassLoader().getParent().getParent()); // null 引导类加载器是C++写的,Java调用不到C++代码
System.out.println(String.class.getClassLoader()); // null
System.out.println(DNSNameService.class.getClassLoader()); // ext包中的类,通过ExtClassLoader加载
// C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar 根加载器加载
// C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext ExtClassLoader加载
// 自定义包下的自定义类: 应用程序类加载器加载
}
}
执行结果
自己写一个java.lang.String类,会发生什么事情?
package java.lang;
public class String {
public static void main(String[] args) {
String s = new String();
System.out.println(s.toString());
}
}
上面代码会编译报错:
明明String类中写了main方法,为什么报错找不到main方法呢? 说明JVM压根就没加载我们自己写的String类,这是出于安全考虑,最终执行的是 BootStrap类加载器去加载rt.jar中的String类, 这是由于双亲委派机制;
当类加载器要加载一个类时,会先直接委派给上级的类加载器去加载,上级类加载器又会找到BootStrap加载器加载,
如果BootStrap类加载器没加载到,则委托ExtClassLoader,如果ExtClassLoader 加载器中没找到这个类,则委托应用程序类加载器去加载这个类;
类加载的过程:
-
- 类加载器收到类加载的请求
-
- 将这个请求向上委托给父类加载器去完成,一直向上委托知道BootStrap类加载器
-
- BootStrap类加载器检查是否能够加载当前这个类,能加载则结束,使用当前类加载器,否则通知子类加载器去加载
-
- 重复步骤3 如果最终都没找到,则抛出Class not Found异常
更多参考文章
一篇图文彻底弄懂Class文件是如何被加载进JVM的