类加载器介绍
| 名称 | 加载哪的类 | 说明 |
|---|---|---|
| BootStrap ClassLoader(启动类加载器) | JAVA_HOME/jre/lib | 无法直接访问(C++代码书写的) |
| Extension ClassLoader(扩展类加载器) | JAVA_HOME/jre/lib/ext | 上级为BookStrap,显示为null |
| Application ClassLoader(应用程序类加载器) | classpath | 上级为Extension |
| 自定义类加载 | 自定义 | 上级为Application |
启动类加载器
- -Xbootclasspath表示设置bootclasspath
- 其中/a:.将当前目录追加至bootclasspath之后
- 可以用这个方法替换核心类
- java -Xbootclasspath:<new bootclasspath>{解释:用新路径完全替换掉了原来路径JAVA_HOME/jre/lib}
- java-Xbootclasspath/a:<追加路径>{解释:不替换原有路径,在原有路径后追加路径a}
- java- Xbootclasspath/p:<追加路径 >{解释:在原有路径上前追加}
-
- 启动类加载非java实现,使用的 c/c++实现,嵌套在jvm内部
2.用于加载java的核心类库,用于提供jvm自身需要的类,比如rt.jar里面的类
3.不继承java.lang.ClassLoader,没有父加载器
4.负责加载扩展类加载器和系统应用类加载器,并为他们指定父加载器
5.出于安全考虑,该加载器只负责加载java,javax,sun等开头的类
扩展类加载器
- 是java语言编写,派生于ClassLoader类
- 父类加载器是启动类加载器
- 从java.ext.dirs系统属性所指定的目录中加载类库,或从jdk的安装目录下的jre/lib/ext子目录下加载类库,如果用户创建的 jar放在此目录下,也会有扩展类加载器来加载
应用程序类加载器
- 是java语言编写,派生于ClassLoader类
- 父类加载器是扩展类加载器
- 负责加载 环境变量classpath或者系统属性java.class.path路径下的类库
- 是程序中的默认加载器,一般来说,基本上java的类都是由它加载
自定义类加载器
为什么要定义自已的类加载器呢?
因为Java中提供的默认ClassLoader,只加载指定目录下的jar和class,如果我们想加载其它位置的类或jar时,就只能自定义一个ClassLoader类了。
比如:我要加载网络.上的一个class文件,通过动态加载到内存之后,要调用这个类中的方法实现我的业务逻辑。在这样的情况下,默认的ClassLoader就不能满足我们的需求了,所以需要定义自己的ClassLoader
如何定义类加载器?
继承ClassLoader类,重写findClass( )方法,loadClass( )方法
自定义类加载器注意事项:
自定义类加载器需要去继承ClassLoader类。
JDK1.2之前是重写ClassLoader类中的loadClass方法
JDK1.2以后 是重写ClassLader类中的findClass方法
自定义类加载器的实现,不要去覆盖ClassLoader类的loadClass方法,去实现findClass方法,为什么呢?
双亲委派机制

为什么要使用双亲委托这种模型呢?
考虑到安全因素,因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次 。
比如加载位于rt,jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。
另外我们还可以试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时就被引导类加载器(Bootstrcp ClassLoader)加载,所以用户自定义的ClassLoader永远也无法加载一一个 自己写的String,除非你改变JDK中ClassLoader搜索类的默认算法。
如何判定两个class是相同?
JVM在判定两个Class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。
Proxy.newProxyInstance(ClassI oader)
双亲委派机制源码
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been
loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c =
findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if
class not found
// from the non-null parent class
loader
}
if (c == null) {
// If still not found, then invoke
findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader;
record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1
- t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFro
m(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
本文内容到此结束了,
如有收获欢迎点赞👍收藏💖关注✔️,您的鼓励是我最大的动力。
如有错误❌疑问💬欢迎各位大佬指出。
保持热爱,奔赴下一场山海。🏃🏃🏃
- 点赞
- 收藏
- 关注作者
评论(0)