范例:编写一个简单的反射程序,来观察ClassLoader的存在
package com.ClassLoader;
class Member{}
public class Test {
public static void main(String[] args) {
Class<?> cls = Member.class;
System.out.println(cls.getClassLoader());
System.out.println(cls.getClassLoader().getParent());
System.out.println(cls.getClassLoader().getParent().getParent());
}
}
此时出现了两个类加载器:ExtClassLoader(扩展类加载器)、AppClassLoader(应用程序类加载器)
package com.ClassLoader;
class Member {
@Override
public String toString() {
return "haha";
}
}
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(Member.class.getClassLoader().loadClass("com.ClassLoader.Member").newInstance());
}
}
运行结果:hahaa) Bootstrap(启动类加载器):
由C++实现,属于JVM本身的一部分,无法被Java程序直接引用,
负责加载<Java_Home>/lib下的所有类库(类库名必须能被JVM识别,识别的依旧是按照文件名)eg:rt.jar(JDK基础类,包含所有java开发必备的类如Object类)
除了启动类加载器以外的所有类加载器,均由java语言开发能被java程序直接使用
除了启动类加载器以外,所有类加载器都应有父加载器
b) ExtClassLoader(CLASSPATH):加载第三方程序类库:
负责加载<Java_Home>/lib/ext目录下的所有类库
c) AppClassLoader(自己写的代码):应用程序类加载器:
负责加载classpath中指定的类库
如果程序中没有自定义类加载器,则默认使用AppClassLoader类加载器
d) 自定义类加载器
用户可以自己决定从哪里加载类(本地磁盘、别的磁盘、网络中加载)
类加载器的双亲委派模型
四中类加载器的层次关系
双亲委派模型的工作流程:
当一个类加载器收到类加载请求时,它会先把加载请求委托给父类加载器,如果父类加载器反馈无法加载时,它才会尝试加载此类。所以,在程序中自定义的类加载器请求都会最终走到启动类加载器,这就是双亲委派。
意义:保证java程序的稳定运行。 eg:有一个自定义的类java.lang.Object, 通过双亲委派,便不会再执行自定义的Object。
双亲委派模型不是强制要求,只是JDK建议这样加载类,可以破坏双亲委派模型,如:OSGI 热加载。