面试题思考:如何编写本身的类加载器

类加载器就是负责检索并加载其余Java类或者资源(如文件)的对象,它通常继承于java.lang.ClassLoader这个抽象类(除了BootstrapClassLoader)。java

实际上,程序中全部的类都是经过类加载器进行加载的,而且它们都持有各自类加载器对象的引用,能够经过java.lang.Class的getClassLoader方法获得。mysql

一个程序中的各个类加载器构成了一棵树,位于根部的被称做BootstrapClassLoader,它做为Java虚拟机的一部分,它使用C++语言实现,在程序刚启动时就被加载进来,负责Java标准库的加载,而且只有它能完成该任务。程序员

  
标准扩展(Extension)类加载器负责加载Java_Home /lib/ext或者由系统变量 java.ext.dir指定位置中的类库sql

  
应用程序(Application)类加载器负责加载系统类路径(CLASSPATH)中指定的类库。同时它常被称为系统(System)加载器,由于咱们能够经过getSystemClassLoader()方法来获取它。数据库

  
而由咱们程序员本身编写的类加载器被称为自定义类加载器,若是生成自定义类加载器时没有明确地指出父类加载器,会默认把应用程序(Application)类加载器做为本身的父亲。oracle

  
类加载器的父子关系至关重要,当你指定由一个类加载器加载某一个类时,它会不管如何先把它交给本身的父类加载器来执行,除非父类加载器检索不到这个类,才会开始尝试本身检索和加载。url

显式使用类加载器的最多见例子就是使用JDBC的第一步——加载数据库驱动,如:spa

Class.forName("com.mysql.jdbc.Driver");

或者.net

Class.forName("oracle.jdbc.driver.OracleDriver");

编写目录型类加载器的代码

思路很简单,把指定目录追加到类加载器的类路径中便可。code

public static ClassLoader createClassLoader(String dirname) throws java.io.IOException {
    java.net.URL[] url = new java.net.URL[1];
    java.io.File file;
    if (dirname.endsWith("/")) {
        file = new java.io.File(dirname);
    }
    else {
        // 对于目录的路径,最后必需要有'/'
        file = new java.io.File(dirname + "/");
    }
    url[0]= file.toURI().toURL();

    ClassLoader parent = ClassLoader.getSystemClassLoader();
    java.net.URLClassLoader loader = new java.net.URLClassLoader(url, parent);

    return loader;
}

下面以一个实例演示如何使用该类加载器,首先建立一个class目录的类加载器,而后获取test.Main类对象,并调用它的main方法。

private void foo() throws Exception {
    ClassLoader loader = createClassLoader("./class/");
    Class<?> cls = Class.forName("test.Main", true, loader);
    java.lang.reflect.Method method = cls.getMethod("main", new Class[]{String[].class});

    method.invoke(null, new Object[]{null});
}

虽然此次演示的是目录,但对于jar文件和zip文件一样能够经过URLClassLoader来加载。

相关文章
相关标签/搜索