类加载器

一、什么是类加载器(ClassLoader)
类加载器可以把类加载到Java虚拟机中,对于任意的一个类,都需要由加载它的类加载器和这个类本身一同确立起在Java虚拟机中的唯一性
比较两个类是否”相等“,只有在这两个类是由同一个类加载器加载的前提在才有意义,否则,即使这两个类源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类必定不相等。这里所指的“相等”包括代表类的Class对象的equal方法、isAssignableFrom()、isInstance()方法及instance关键字返回的结果。
如上图,此时虽然是同一个Person.class ,但是被不同的类加载器加载到Java虚拟机,那么加载后的这两个 Person类是不”相等“,因为它们分别在两个不同的命名空间中。
注:如果上面两个类的是否”相等“比较你没看懂的话,后面自定义类加载器的时候我们会演示一下这个例子,进行简单说明。

二、类加载器分类

一张图看懂类加载器分类:
上图的类加载器主要分为四类:
Bootstrap ClassLoader : 启动类加载器,这 个类加载器使用C++语言实现,是虚拟机自身的一部分
Extension ClassLoader : 扩展类加载器
Application ClassLoader :应用程序类加载器
User ClassLoader :自定义类加载器
 
 
public class ClassLoaderDemo {
 
     public static void main ( String [ ] args ) {
 
         // ClassLoaderDemo 的类加载器
        System . out . println ( ClassLoaderDemo . class . getClassLoader ( ) ) ;
 
         // 打印每个 ClassLoader的父加载器
        ClassLoader classLoader = ClassLoaderDemo . class . getClassLoader ( ) ;
         while ( classLoader != null ) {
            System . out . println ( classLoader ) ;
            classLoader = classLoader . getParent ( ) ;
         }
        System . out . println ( classLoader ) ;
     }
}
-- - 打印结果:
sun . misc . Launcher$AppClassLoader @18b4aac2
sun . misc . Launcher$AppClassLoader @18b4aac2
sun . misc . Launcher$ExtClassLoader @1540e19d
null
 

启动类加载器(根加载器)

主要负责加载存放在JAVA_HOME/jre/lib/rt.jar里面所有的class文件,或者被-Xbootclasspath参数所指定路径中以rt.jar命名的文件。启动类加载器无法被Java程序直接引用,如果在编写自定义类加载时,需要把加载的请求委派给启动类加载器,那么直接使用null代替即可。
例如:
MyClassLoader myClassLoader = new MyClassLoader ( null ) ; //父加载器使用启动类加载器
public MyClassLoader ( ClassLoader parent ) {
super ( parent ) ; //指定该类加载器的父类加载器
}

扩展类加载器

这个加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载AVA_HOME/lib/ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。
 

应用程序类加载器

这个加载器由sun.misc.Launcher$AppClassLoader实现,它负责加载classpath对应的jar及目录。如果应用程序没有自定义过自己的类加载器, 一般情况下这个就是程序中默认的类加载器。
 

自定义类加载器

用户定制自己的类加载器,继承ClassLoader,根据自己的需要进行设计和实现,比如需要从指定的路径下读取class文件进行加载等。
知道上面这些内容,你就应该联想到为什么在学习Java的时候首先要配置Java环境变量了。这就是知其所以然的过程。
 
思考 :这么多类加载器,那么如何保证一个类不被重复加载,只被加载一次呢?主要是通过双亲委派机制
 
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有父类加载器反馈自己无法完成这个加载请求(它搜索的范围中没有找打所需的类)时,子加载器才会尝试自己去加载。
如下示意图:
在说明一下: 加载一个类的时候。首先自定义类加载类器先会委派给应用程序类加载器(Application ClassLoader),应用程序类加载器会委派给扩展类加载器(Extension ClassLoader),扩展类加载器会委派给启动类加载器(Bootstrap ClassLoader)去加载,这时候如果启动类加载器加载成功,则加载结束。如果加载失败,则交给扩展类加载器去加载,如果扩展类加载器加载成功,则加载结束。如果加载失败,则交给应用程序类加载器,如果应用程序类加载器加载成功,则加载结束。如果加载失败,则交给自定义类加载器。如果自定义类加载器加载成功,则加载结束。否则加载失败,会报ClassNotFoundExecption异常,结束。
每个类加载器都有自己的管辖范围(命名空间),并在自己的管辖范围做好自己的事情
 
双亲委派模型还有一个优点是能提供软件系统的安全性,在这个机制下,用户自定义的类加载器不可能加载应该由父类加载器加载的可靠类,从而防止不可靠甚至是恶意的代码代替父类加载器加载可靠代码。如 java.land.Object 类总是由启动类加载器进行加载,其他任何用户自定义的类加载器都不可能加载含有恶意代码的java.land.Object 类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值