JVM(6)类加载器

加载步骤中虚拟机需要完成以下三件事:
1、通过一个类的全限定名来获取定义此类的二进制字节流。
2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
其中实现“通过一个类的全限定名来获取定义此类的二进制字节流”这个步骤的代码模块称为类加载器。

每一个类加载器,都拥有一个独立的类名称空间。因此,比较两个类是否相等,只有在这两个类是由同一个类加载器加载的前提下才有意义。

类加载器可以分为:启动类加载器,扩展类加载器,应用程序类加载器,自定义类加载器。这几种类加载器是相关配合进行加载的,他们之间的关系称为双亲委派模型。双亲委派模型要求除了顶层的启动类加载器外,其他的类加载器都有自己的父类加载器。这些类加载器之间的父子关系一般不会以继承的关系来实现,而是都是使用组合关系来复用父加载器的。

这里写图片描述

启动类加载器:加载<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数指定的路径,并且是虚拟机识别的类库。
扩展类加载器:加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的类库。
应用程序加载器:负责加载用户类路径上所指定的类库。如果应用程序没有自定义过自己的类加载器,一般情况下这个就是程序中的默认类加载器。
如果一个类加载器收到了类加载的请求,先传到父类尝试加载,每次都先依次向上传递,只有当父类加载器反馈无法加载时,子类才会尝试加载。

用双亲委派模型的好处:java类有了优先级的层次关系,保证高层的类是用同一个类加载的,避免混乱。

双亲委派模型的实现代码:

protected synchronized Class<?> loadClass(String name,boolean resolve)throws ClassNotFoundException{
    //检查请求的类是否被加载过了
    Class c = findLoadedClass(name);
    if(c == null){
        try{
            if(parent != null){
                c = parent.loadClass(name,false);
            }else{
                c = findBootstrapClassOrNull(name);
            }
        }catch(ClassNotFoundException e){
            //如果父类加载器抛ClassNotFoundException异常,说明父类加载器无法完成加载请求
        }
        if(c == null){
            //父加载器无法加载时,再调用自身的findClass方法进行加载
            c = findClass(name);
        }
    }
    if(resolve){
        resolveClass(c);
    }
    return c;
}

JDK中也有破坏双亲委派模型的情况,双亲委派模型并不是一种强制约束模型。

猜你喜欢

转载自blog.csdn.net/wee616/article/details/78297647