jvm classloader 原理

来源:互联网 发布:炒股模拟软件 知乎 编辑:程序博客网 时间:2024/05/17 03:35
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加载器的引用)

0 0