URLClassLoader使用以及特性详解

类加载器类型

Java中有4种类加载器:

    BootstrapClassLoader 最顶层的加载类,主要加载核心类库(c++实现) ExtentionClassLoader 扩展的类加载器 AppClassLoader也称为SystemAppClass 加载当前应用的classpath的所有类。 自定义类加载器。

注意:classpath即为java编译的源文件以及一些第三方库所在的文件夹或jar包。详细了解见

加载顺序

双亲(parent)委托机制

遇到加载请求,先把这个请求交给父加载器加载。只有父类加载器找不到class文件,子类才可以加载。所以加载顺序一般是 BootstrapClassLoader -> ExtentionClassLoader -> AppClassLoader -> 自定义类加载器(默认)

父加载器不是父类

加载器类中有一个变量指向父加载器,更继承没啥关系。一般在加载器的构造函数中可以指定父加载器,没指定则默认为AppClassLoader ,指定为null父加载器则为BootstrapClassLoader。

URLClassLoader

可以指定一串路径,然后再些路径下面寻找将要加载的类。这个类加载器如果没有指定的话父类加载器也是AppClassLoader

举个例子。 我们有一个Hello.class文件,位于d:/目录下

public class Hello {
          
   
    public Hello() {
          
   
        System.out.println("hello!!!!!!!!!");
    }
}

通过URLClassLoader加载这个类

public class ClassLoaderTest {
          
   

    @Test
    public void urlClassLoaderTest() throws Exception {
          
   
        File file = new File("d:/");
        URL url = file.toURI().toURL();
        ClassLoader loader=new URLClassLoader(new URL[]{
          
   url});
        Class<?> clazz = loader.loadClass("Hello");
        System.out.println("当前类加载器"+clazz.getClassLoader());
        System.out.println("父类加载器"+clazz.getClassLoader().getParent());
        clazz.newInstance();
    }
}

输出:

如果在当前的classpath也放置一个Hello.class文件,那么就会被APPClassLoader加载,而且加载不到d盘的那个文件。

public class Hello {
          
   
    public Hello() {
          
   
        System.out.println("this is another hello class");
    }
}

输出: 但是若把URLClassLoader的父类设置为启动类加载器,这样就避免了委派给AppClassLoader时加载了classpath下的同名类文件。

@Test
    public void urlClassLoaderTest() throws Exception {
          
   
        File file = new File("d:/");
        URL url = file.toURI().toURL();
        ClassLoader loader=new URLClassLoader(new URL[]{
          
   url},null);//设为null表示由根加载器加载
        Class<?> clazz = loader.loadClass("Hello");
        System.out.println("当前类加载器"+clazz.getClassLoader());
        System.out.println("父类加载器"+clazz.getClassLoader().getParent());
        clazz.newInstance();

    }

输出:

与反射创建类的区别

反射创建常用Class.forName,通过类的全限定类名创建,但是只能创建classpath内的类,如果一个类不在classpath中。就只能使用类加载器来创建了。 参考:

经验分享 程序员 微信小程序 职场和发展