类加载器:
java中的类加载器.关于类加载器的内容大体上可以分为以下几部分:
1.类加载器的作用
2.类加载器的层次结构
3.类加载器的委托机制
4.自定义类加载器
我的总结就从这几个方面开始入手好了.
1.类加载器的作用
在说它作用的时候就得先知道JAVA中程序执行的过程了.在JAVA中要想一个程序
执行必须经过这么几个步骤:先由编译器把原文件编译成CLASS文件.这一步骤要
做的事情主要是把原程序转换成JVM能够看懂的信息,并进行必要的填充和去除一
些信息;下一步是把CLASS文件加载到内存中,在这一过程中会由类加载器把CLASS
文件进行一些必要的增删信息,并加载到内存中,这时一个CLASS文件在内存中的
表现形式就是字节码的形式了.最后再由JVM对这些字节码进行执行.(当然了,这只
是我的理解,也许有什么地方不正确,希望知道的同学前辈们指点).
通过这个过程我就知道了,啊,原来类加载器的作用就是把类文件进行必要的转换
并加载到内存中!
知道了类加载器的作用,现在得知道它的JAVA中的层次结构了.
2.类加载器的层次结构.
JAVA中的类加载器其实也是一种类,那么很自然的它们也会由类加载器加载,所以是
谁加载谁这样的结构就形成了一个层次的结构,它们呈现出这样的一种层次结构:
BootStrap --Loader-> ExtClassLoader --Loader-> AppClassLoader.
这里的层次结构只是JAVA提供的,其它自定义的不算,现在分别看看这三个JAVA提供
的类加载器吧!
BootStrap :负责加载JRE/lib/rt.jar中的类
ExtClassLoader :负责加载JRE/lib/ext/中的所有jar包中的类.
AppClassLoader :负责加载ClassPath指定的目录或.jar包中的类
呵呵,前面都说过类加载器其它也是一种类,那么最顶层的BootStrap又是由谁加载的
呢?这里我要说的是BootStrap是比较特殊的,它不是一个类,它是用C++写的一段代码.
它是直接嵌套在JVM内核中的.一运行JVM时它就存在了.
好,把类加载器的层次结构理清楚了以后是时候看看它们之间对于类加载的机制了.
3.类加载器的委托机制
对于类之间的加载机制,实际上就是一种加载顺序的问题,而在JVM中采用的就是委托
机制.委托机制控制类加载的顺序是按照这样的一种策略来的:
1.先由当前线程的类加载器去加载第一个类,(在没有指定类加载器时,还可以直接调
用ClassLoader.loaderClass()方法来指定用哪个类加载器来加载这个类.)但是它并
不是直接加载而是委托它的父类加载,父类再以同样的方法往上委托
2.如果父类加载成功,则返回加载成功的标识,子类就不再加载.
如果父类在它所加载的位置没有找到,则返回类没找到标识,子类再加载.
如果都没有找到,则抛出 ClassNotFoundException 异常.
3.如果在这个类里面引用了别的类,那么再使用这个类加载器去加载它所引用的类(重复1-2)
通过这个过程可以很清楚的看到,它就是一步步的往上委托,只有当上面的父类都没能加载
到的时候才由发起者加载,如果发起者也加载不到才抛出ClassNotFoundException 异常.
这样做的好处就是方便于集中管理,不会存在重复加载的问题,但是当类加载器的体系过大
时,则消耗的时间就会很多了,这就是一个递归的过程.
恩,委托机制也差不多了,现在可以动手自己写一个类加载器了.
4.自定义类加载器
在JAVA中,要想自定义类加载器就需要继承ClassLoader类,并覆盖它的findClass方法,
在 ClassLoader 类中,loadClass方法的实现已经所委托机制所需要的代码写好了,而
findClass方法就是专门负责加载类的,所以如果是需要使用委托机制就可以只用覆盖
findClass方法就成了,而如果想让类加载器按照自己的想法加载类则可以覆盖
loadClass方法.下面是自定义的类加载器代码(最简单的):
import java.io.ByteArrayInputStream;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;public class MyClassLoader extends ClassLoader {//这个classDir用于指定从哪个目录下加载类private String classDir;public MyClassLoader(){ }public MyClassLoader(String classDir){ this.classDir =classDir;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException { // TODO Auto-generated method stub// 得到类的完全路径 String classPath = classDir+"\\"+name+".class"; //定义一个文件输入流,一个字节数组,一个字节数组长度的变量,用于调用defineClass方法做准备 FileInputStream fis = null; byte[] b = null; int len = 0; try { fis = new FileInputStream(classPath); len = fis.read(b); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally//关闭文件输入流 { if(fis!=null) try { fis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return defineClass(name,b, 0, len);}}
有一点我还是不太明白,那就是如何把这个自定义的类加载器挂到那几个JVM提供的类加载
器上面,张老师所讲的只是继承 ClassLoader 类,默认是挂在AppClassLoader类加载器上的,
还望知道的同学或前辈们指点一二!谢谢,
对于类加载器的知识总结就到这儿了.