4、演示类加载器的树状结构
每个 Java 类都维护着一个指向定义它的类加载器的引用,通过 getClassLoader()方法就可以获取到此引用下面通过递归调用 getParent()方法来输出全部的父类加载器。- public class ClassLoaderTree {
-
- public static void main(String[] args) {
- ClassLoader loader = ClassLoaderTree.class.getClassLoader();
- while (loader != null) {
- System.out.println(loader.toString());
- loader = loader.getParent();
- }
- }
- }
复制代码输出结果 sun.misc.Launcher$AppClassLoader@9304b1 sun.misc.Launcher$ExtClassLoader@190d11第一个输出的是 ClassLoaderTree类的类加载器,即系统类加载器。它是 sun.misc.Launcher$AppClassLoader类的实例;第二个输出的是扩展类加载器,是 sun.misc.Launcher$ExtClassLoader类的实例。需要注意的是这里并没有输出引导类加载器,这是由于有些 JDK 的实现对于父类加载器是引导类加载器的情况,getParent()方法返回 null 5、加载流程分析
当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢? 首先当前线程的类加载器去加载线程中的第一个类。 如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。 还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。 每个类加载器加载类时,又先委托给其上级类加载器。 当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢? 对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。 每个ClassLoader本身只能分别加载特定位置和目录中的类,但它们可以委托其他的类装载器去加载类,这就是类加载器的委托模式。类装载器一级级委托到BootStrap类加载器,当BootStrap无法加载当前所要加载的类时,然后才一级级回退到子孙类装载器去进行真正的加载。当回退到最初的类装载器时,如果它自己也不能完成类的装载,那就应报告ClassNotFoundException异常。
有一道面试,能不能自己写个类叫java.lang.System。 通常是不可以的,由于类加载器的委托机制,会先将System这个类一级级委托给最顶级的BootStrap,由于BootStrap在其指定的目录中加载的是rt.jar中的类,且其中有System这个类,那么就会直接加载自己目录中的,也就是Java已经定义好的System这个类,而不会加载自定义的这个System。 但是还是有办法加载这个自定义的System类的,此时就不能交给上级加载了,需要用自定义的类加载器加载,这就需要有特殊的写法才能去加载这个自定义的System类的。
6、自定义类加载器 1)、自定义的类加载器必须继承抽象类ClassLoader,要覆写其中的findClass(Stringname)方法,而不用覆写loadClass()方法。 2)、覆写findClass(Stringname)方法的原因: 是要保留loadClass()方法中的流程,因为loadClass()中调用了findClass(Stringname)这个方法,此方法返回的就是去寻找父级的类加载器。 在loadClass()内部是会先委托给父级,当父级找到后就会调用findClass(Stringname)方法,而找不到时就会用子级的类加载器,再找不到就报异常了,所以只需要覆写findClass方法,那么就具有了实现用自定义的类加载器加载类的目的。 流程: 父级-->loadClass-->findClass-->得到Class文件后转化成字节码-->defind()。 3)、编程步骤: 编写一个对文件内容进行简单加盟的程序 编写好了一个自己的类加载器,可实现对加密过来的类进行装载和解密。 编写一个程序,调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类,程序中除了可使用ClassLoader的load方法外,还能使用放置线程的上线文类加载器加载或系统类加载器,然后在使用forName得到字节码文件。
|