什么是类加载器

类加载器负责所有类的加载,系统为所有被载入内存的类生成一个java.lang.Class实例。一旦一个类被载入到JVM中,同一个类就不会被再次载入。但是如何判断“同一个类”呢?

正如一个对象有唯一标示一样,一个被载入JVM的类也拥有唯一的标示。在Java中一个类用其全限定名(包名+类名)作为标示;但是在JVM中,一个类用其全限定名和类加载器作为唯一标示,也就是说两个类加载器加载的同名类是不同的

当JVM启动时,会形成由三个类加载器组成的初始类加载器层次结构:



Bootstrap ClassLoader:根加载器



Extension ClassLoader:扩展类加载器



System ClassLoader:系统类加载器



Bootstrap ClassLoader

引导(也称为原始或根)类加载器,它负责加载Java的核心类。在Sun的JVM中,当执行java.exe命令是,使用Xbootclasspath选项或使用-D选项指定sun.boot.class.path系统属性值可以指定加载附加的类

根类加载器肥城特殊,它并不是java.lang.ClassLoader的子类,而是有JVM自身实现的。

Extension ClassLoader

扩展类加载器,负责加载JRE的扩展目录(%JAVA_HOME%\jre\lib\ext或者有java.ext.dirs系统属性指定的目录)中JAR包的类。

通过这种方式,就可以为JAva扩展核心类以外的新功能面只要把自己开发的类打包成JAR文件,然后放入JAVA_HOME\jre\lib\ext路径即可。

System ClassLoader

系统(应用)类加载器,它负责在JVM启动是加载 来自java命令的-classpath选项、java.class.path系统属性,或CLASSPATH环境变量所指定的JAR包和类路径。程序可以通过ClassLoader的静态方法getSystemClassLoader()来获得系统类加载器。如果没有特别指定 ,则用户自定义的类加载器都以其作为父加载器。

类加载器机制

JVM的类加载机制主要与三种:



全盘负责:就是当一个类加载器负责加载某个Class时,该Class所以来的和引用的其他Class也将有该类加载器负责加载,除非明确指出使用另一个类加载器来加载



父类委托:先让parent(父)类加载器加载该Class,只有在父类加载器无法加载该类时才会尝试自己加载该类。



缓存机制:会保证所有加载过的Class都会被缓存,当程序需要是由牧歌 Class时,类加载器先从缓存区搜索该Class,只有当缓存区中不存在该Class对象时,系统 才会读取该类对应的二进制数据,并将其转换Class对象,存入缓存区中。这就是为什么修改了 Class后,必须重新启动JVM,程序所做的修改才会生效的原因



类加载器之间的父子关系并不一定是继承上的父子关系,也有可能是包装关系,这里的父子关系时类加载器实例之间的关系



JVM的跟类加载器并不是Java实现的,而且由于程序通常无需访问根类加载器,因此使用扩展类加载器访问父类加载会返回null。但是实际上,扩展类加载器的父类加载器是根类加载器 




java相同名称的导入文件获取到的是以前的_类加载器

java相同名称的导入文件获取到的是以前的_JVM_02

// 获取系统类加载器的父类加载器:得到扩展类加载器
        ClassLoader extensionLader = systemLoader.getParent();
System.out.println("扩展类加载器:" + extensionLader);
System.out.println("扩展类加载器的加载路径:"
            + System.getProperty("java.ext.dirs"));
System.out.println("扩展类加载器的parent: "
            + extensionLader.getParent());// 返回null


View Code


类加载器加载Class大致要8个步骤:



1:检测此Class是否载入过(即缓存区中是够有此Class),如果有则进入第8步,否则继续执行第2步。



2:如果父类加载器不存在(如果没有父类加载器,则,要么paret一定是根类加载器,要么本身就是根类加载器),则跳到第4步执行;否则,接着执行第3步。



3:请求使用父类加载器去加载目标类,如果成功载入则跳到第8步,否则跳到第5步执行。



4:请求使用根类加载器加载目标类,如果成功加载则跳到第8步,否则跳到第7步。



5:当前类加载器尝试寻找Class文件(从与此ClassLoader想过的类路径中寻找),如果找到则执行第6步,否则,跳到第7步。



6:从文件中载入Class,成功加载后跳到第8步。



7:抛出ClassNotFoundException异常。



8:返回对应的java.lang.Class对象。



其中,第5、6允许重写ClassLoader的findClass()方法来实现自己的载入策略,深知重写loadClass()方法来实现自己的载入过程。

加载步骤如图所示(请放大网页查看[Ctrl+滚轮]):

java相同名称的导入文件获取到的是以前的_java_03