类加载器是Java组成的重要基石,对于任何一个类,在确定其的唯一性的时候,都需要加载它的类加载器和这个类的本身
也就是说,如果一个类是否具有相等性,只有在这两个类都被同一个类加载器加载的时候才能比较其的唯一性,哪怕是同一个Class文件,但是被不同的类加载器加载了,两个类必然不同
其次就是Java中的重点,双亲委派模型,只存在两种不同的类加载器,一种是启动类加载器,本身靠的是C++语言实现,是虚拟机自身的一部分,另一种就是其他的类加载器,全部由Java语言实现,继承自java.lang.ClassLoader
而在实际开发过程中,整个了加载器
启动类加载器,只负责将存放<JAVA_HOME>\lib目录中的类库加载到虚拟机内存中,而且是按照文件名识别,稍不符合的就无法进行加载
扩展类加载器(Extension ClassLoader0,负责加载 java系统变量所指定的路径的中的类库
应用程序加载器(Application ClassLoader) ,不指定加载器的话,一般开发者使用的都是这个类加载器
其组成的模型大致如下
双亲委派就是,一般接收到一个类的时候,不会尝试自己去读取加载,而是扔给自己的父加载器,一层层的递归向上,直到父类确定自己无法加载这个的时候,才会尝试自己去加载的
双亲委派机制的最大好处就是可以有效的避免一个类的多次加载的问题,避免了具有多个类的实例,不然,每个类加载器都加载一个Object对象,这不就乱套了
在整个Java发展的过程中,曾经破坏过三次双亲委派模型,这里说的破坏不是贬义词,而是一种对于破坏的肯定
1.在Java的刚刚推出1.2的时候,为了妥协之前的ClassLoader,虚拟机在类加载的时候会利用loadClass()方法调用加载器的私有方法 loadClassInternal()方法,而现在已经不要求重写loadClass方法了,而是利用findClass()方法完成加载了
2.在基础类回调用户的自定义数据的时候,无法去加载,也不知道是谁加载的,只能创建了一个上下文类加载器,这个类加载器可以通过Thread类来进行设置,如果创建时候线程还没有设置时候会从父线程中继承一个,利用这个就可以做一些舞弊的事情了,逆向的使用类加载器,常见的使用场景有JDBC JNDI等
3.在Java进行模块化的时候,或者说热部署的时候,希望在更换某一个Bundle的时候,不需要进行重启或
于是在出现了这个概念之后,类加载器就成为可更加的复杂,成为了一个网状结构,现在的搜索可以分为
1.对Java.*开头的类委派给父类加载器加载
2.将委派列表名单内的类委派给父类加载器加载
3.Import列表中类委派给Export这个类的Bundle类加载器的加载
4.查找当前Bundle的ClassPath,使用自己的类加载器
5.查找是否在自己的Fragment Bundle之中,在的话就委派给Fragment Bundle类加载器加载
6.查找Dynamic Import列表的Bundle,委派给Bundle的类加载器加载
7.类查找失败