1,类加载器构成
Bootstrap(启动类加载器 $JAVA_HOME/lib)---extension(ExtClassLoader扩展类加载器$JAVA_HOME/lib/ext)---system(AppClassLoader系统类加载器Classpath)
2,加载机制
双亲委派机制,某个特定的类加载器接受到加载请求时,首先将加载请求委托给父类加载器,一次递归,父类加载器可以完成加载任务,则成功返回,只有父类无法完成加载时,才自己去加载,jvm默认的双亲委派机制通过ClassLoader的loadClass方法来实现的。方法如下

// 首先判断该类型是否已经被加载

        Class c = findLoadedClass(name);

        if (c == null) {

            //如果没有被加载,就委托给父类加载或者委派给启动类加载器加载

            try {

                if (parent != null) {

//如果存在父类加载器,就委派给父类加载器加载

                    c = parent.loadClass(name, false);

                } else {

//如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native Class findBootstrapClass(String name)

                    c = findBootstrapClass0(name);

                }

            } catch (ClassNotFoundException e) {

        // 如果父类加载器和启动类加载器都不能完成加载任务,才调用自身的加载功能

                c = findClass(name);

            }

        }




注意:扩展类加载器的父加载器为为NUL,引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用




如何实现我们的自定义类加载器呢?



实现自定义加载器其它很简单。只要实现ClassLoader的findClass()方法就行了。



大概如下:



findClass(String name){

    byte[] buffer=//读取文件的字节数组

    return defineClass(buffer,0,buffer.length);

}





当自定义类加载器加载的类有继承相应的类或实现相应接口的话,必须把相应的父类或接口拷贝到同一路径。因为类加载器在加载子类时,会同时加载父类。



关于类的转型问题:



由于类加载器是相互隔离的,当classLoaderA加载了A类,classLoaderB也加载了A类。这个类对象是不能互相转型的。会报ClassCastException异常。



假如自定义类加载器加载A类时,而A类又实现了接口B时,我们是可以将A类的实例转成B接口的。原因是类加载器在加载A类时,会同时加载A类的所有父类(包括接口).



JAVA类加载器采用了委托模式。当一个类对象己经被加载了,就不会在去加载该类。还是直接返回。那么如何重新加载这个类呢?



实现自定义的类加载器,当类加载完成后。调用相应方法,然后在去掉相应类加载器的引用。这样类不会在存在类加载器中了。



比如:classLoaderA=null(去掉A加载器的引用)