javac: *.java--->*.class(源代码-->字节码)
java: *.class--->机器码
classpath:类加载路径
一、认识ClassLoader
package classLoader;
public class Test {
public static void main(String[] args) {
Class<?> cls=Test.class;
System.out.println(cls.getClassLoader());
//取得父类加载器
System.out.println(cls.getClassLoader().getParent());
System.out.println(cls.getClassLoader().getParent().getParent());
}
}
结果:
类加载器的概念:通过一个类的全名称来获取此类的二进制字节流,实现这个操作的代码模块称为类加载器。
二、JDK中内置的三大类加载器
1.BootStrap(启动类加载器)
1)使用C++实现,是JVM的一部分。其它所有类加载器均使用Java实现。
2)负责将存放于Java_HOME\lib目录下的能被JVM识别的类库(rt.jar--存放了Java所有基础类库,java.lang,java.util)加载到JVM中。
3)启动类加载器无法被Java程序直接引用。
说明:该类加载器没有父加载器。它并没有继承java.lang.ClassLoader类。
2.ExtClassLoader(扩展类加载器)
1)使用Java实现,并且可以被Java程序直接引用。
2)加载Java_HOME\lib\ext目录下能被识别的类库。
说明:它的父类加载器为根类加载器。如果把用户创建的jar文件放在Java_HOME\lib\ext目录下,也会自动由扩展类加载器加载。扩展类加载器是纯Java类,是java.lang.ClassLoader类的子类。
3.AppClassLoader(应用程序/系统类加载器)
1)负责加载用户路径(classpath)上指定的类库。
2)如果应用程序中没有自定义类加载器,则此类加载器就是Java程序中默认的类加载器。
说明:它是纯Java类,是java.lang.ClassLoader类的子类。
4.三者的关系
三、双亲委派模型(JDK1.2)
1.定义
JDK内置的三种类加载器与用户自定义类加载器之间的层次关系称为类加载器的双亲委派模型。要求除了顶层的父类加载器外,其余的类加载器都应该有自己的父类加载器。
2.类加载器的执行流程
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException方法中的一段代码:
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
}
因此,执行流程为:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载此类,而是把类加载请求委托给父类加载器完成,每一个层次类加载器均是如此。只有当父类加载器无法完成加载请求时(在自己搜索范围内没有找到此类),子加载器才会尝试自己去加载。
加载类之间的父子关系实际上指的是加载器对象之间的包装关系,而不是类之间的继承关系。一对父子加载器可能是同一个类加载器的两个示例,也可能不是。在子加载器中包装了一个父类加载器。
3.双亲委派模型的作用
保证Java程序稳定运行。Java中基础类库一定由顶层BootStrap类加载器加载。因此,诸如Object等核心类在各种类加载器环境下都是同一个类。
4.比较两个类相等的前提
这两个类必须是同一个类加载器加载的前提下才有意义。
四、自定义类加载器
要创建自己的类加载器,只需扩展java.lang.ClassLoader类,然后覆写它的findClass(String name)方法,该方法根据参数指定的类的名字,返回对应的Class对象的引用。