类加载器的分类以及双亲委派机制

类加载器分类

Java虚拟机中支持两种加载器:引导类加载器和自定义类加载器。这里的自定义类加载器包括了JVM内置的扩展类加载器和应用类加载器。

虚拟机自带的类加载器

JVM内置了三种类加载器,Java程序的绝大多数类都使用这三个类加载器完成加载。这三个类加载器分别是:启动类加载器、扩展类加载器、应用类加载器
启动类加载器
启动类加载器(Bottstrap ClassLoader)
(1)这个类加载器使用C/C++写成,它用来夹在Java核心类库,在Java程序中是获取不到的
(2)它不继承自java.lang.ClassLoader,没有父类加载器
(3)它加载扩展类加载器和应用类加载器,并成为后两者的父类加载器
(4)它只加载包名为java、javax、sun等开头的类
扩展类加载器
扩展类加载器(Extension ClassLoader)
(1)它属于自定义类加载器,由Java语言编写而成,派生于ClassLoader类
(2)它的父类加载器为启动类加载器
应用类加载器
应用类加载器(AppClassLoader)
(1)它属于自定义类加载器,由Java语言编写而成,派生于ClassLoader类
(2)它的父类加载器为扩展类加载器
(3)它负责加载classpath环境变量下的类。我们在安装JDK配置环境变量时就是配置这个类加载器的加载路径

用户自定义的类加载器

Java程序中的类几乎都是虚拟机自带的类加载器加载的
为什么需要自定义类加载器?
原因:
(1)隔离加载器
(2)修改类的加载方式
(3)扩展加载源
(4)防止源码泄露

关于ClassLoader

ClassLoader是一个抽象类,其后所有的类加载器都继承自ClassLoader(不包括启动类加载器)
getParent()方法是返回该类加载器的父类加载器如果该类加载器为扩展类加载器,扩展类加载器的父类加载器是启动类加载器。所以如果对扩展类加载器对象使用这个方法,是获取不到启动类加载器的,返回值为null

public class Test {
    public static void main(String[] args) {
        //获取当前类的类加载器
        ClassLoader c = Test.class.getClassLoader();
        System.out.println(c);
        //运行结果表明,当前类的类加载器为AppClassLoader应用类加载器
        //现在获取应用类加载器的父类加载器
        ClassLoader c1 = c.getParent();
        System.out.println(c1);
        //运行结果表明,当前类加载器的父类加载器为PlatformClassLoader扩展类加载器
        ClassLoader c2 = c1.getParent();
        System.out.println(c2);
        //输出null说明扩展类加载器的父类是启动类加载器,启动类加载器是获取不到的,所以输出结果为null
    }
}

Java中获取类加载器的四种方式

方式一:class.getClassLoader()获取当前类的类加载器
方式二:Thread.currentThread().getContextClassLoader()多线程中根据上下文获取类加载器
方式三:ClassLoader.getSystemClassLoader()获取系统的ClassLoader
方式四:DriverManager.getCallerClassLoader()获取调用者的类加载器
以上四种方式均无法获取启动类加载器,因为启动类加载器不是ClassLoader的子类,不是用Java语言写成的,因此无法获取到

双亲委派机制

工作原理:
(1)如果一个类加载器收到了类加载的请求,它并不会自己先去加载,而是把这个请求委托给其父类加载器去执行
(2)如果父类加载器还存在父类加载器,则继续向上委托,直到委托给启动类加载
(3)如果父类加载器可以完成加载,就成功返回;如果父类加载器无法完成加载请求,子类才会尝试加载
图解:
类加载器的分类以及双亲委派机制
双亲委派机制的优势:
(1)避免类的重复加载
(2)保护安全,防止核心API被随意篡改

其他内容

(1)在JVM中表示两个class对象是否为同一个类的两个必要条件:
①类名(指完整的类名,带包名)必须完全相同
②加载这个类的ClassLoader(指ClassLoader实例对象)必须相同
(2)如果一个类是由ClassLoader及其子类加载的,则JVM会将这个类加载器的一个引用作为类信息的一部分保存在方法区中。当解析一个类型到另一个类型时,JVM需保证这两个类型的类加载器是相同的
(3关于类的主动使用和被动使用
Java中对类使用方式有两种:主动使用和被动使用
主动使用的7种情况:
①类实例化
②访问某个类或接口的静态变量,以及对这个静态变量赋值
③调用类的静态方法
④反射
⑤初始化一个类的子类
⑥JVM启动时被标明为启动类的类
⑦JDK7开始提供的动态语言支持
除了以上7种情形,其他均为被动使用
主动使用和被动使用的区别:
被动使用不会导致类初始化,主动使用会导致类初始化。类初始化是类加载过程的第三个阶段

上一篇:再谈类的加载器


下一篇:数据结构(树链剖分):BZOJ 4034: [HAOI2015]T2