zoukankan      html  css  js  c++  java
  • 类加载器和双亲委派模型

    什么是类加载器?

    类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作在Java虚拟机外部实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为“类加载器”。

    类与类加载器之间的关系

    对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。也就是说:比较两个类是否“相等”,只有在这个两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那么这两个类就必定不想等。

    package cn.hao.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class ClassLoaderTest {
    
        public static void main(String[] args) throws Exception {
            ClassLoader myLoader = new ClassLoader() {
                @Override
                public Class<?> loadClass(String name)
                        throws ClassNotFoundException {
                    try {
                        String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                        InputStream is = getClass().getResourceAsStream(fileName);
                        if (is == null) {
                            return super.loadClass(name);
                        }
                        byte[] b = new byte[is.available()];
                        is.read(b);
                        return defineClass(name, b, 0, b.length);
                    } catch (IOException e) {
                        throw new ClassNotFoundException(name);
                    }
                }
            };
            Object obj = myLoader.loadClass("cn.hao.test.ClassLoaderTest").newInstance();
            System.out.println(obj.getClass());
            System.out.println(obj instanceof cn.hao.test.ClassLoaderTest);
        }
    }

    运行结果:

    class cn.hao.test.ClassLoaderTest
    false

    使用自定义加载器加载了一个名为“cn.hao.test.ClassLoaderTest”的类,并且实例化了这个类的一个对象。输出结果表明,这个对象确实是类cn.hao.test.ClassLoaderTest实例化出的一个对象,但是这个对象与类cn.hao.test.ClassLoaderTest做所属类型检查的时候返回了false,因为虚拟机中存在了两个ClassLoaderTest类,一个由系统应用程序类加载器加载的,另一个是由自定义的类加载器加载的,虽然都来自同一个Class文件,但是它们依然是两个独立的类,因此做对象所属类型检查的结果是false。

    Java虚拟机中类加载器

    从Java虚拟机的角度来看,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),是虚拟机自身的一个部分;另一种是所有其他类加载器,这些类加载器独立于虚拟机外部,并且全都继承自抽象类java.lang.ClassLoader。

    从Java开发人员的角度看,绝大多数Java程序都会使用到以下3种系统提供的类加载器:

    启动类加载器(Bootstrap ClassLoader):负责将存在<JAVA_HOME>\lib目录中,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(如rt.jar)类库加载到虚拟机内存中。

    扩展类加载器(Extension ClassLoader):复负责加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。

    应用程序类加载器(Application ClassLoader):一般也被称为系统类加载器。负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

    双亲委派模型

    下图显示的类加载器之间的这种层次关系,称为类加载器的双亲委派模型(Parents Delegation Model)。

    双亲委派模型的工作过程:

    如果一个类加载器收到了类加载的契求,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传递到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

    使用双亲委派模型的好处:

    最大和好处就是保证Java中最基础的行为不会被破坏。例如类java.lang.Object,它存在rt.jar之中,无论哪个类加载器要加载这个类,最终都会委派给处于模型最顶层的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一类。相反,如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户自己编写了一个名称为java.lang.Object的类,并放在CLASSPATH中,那系统中会将出现多个不同的Object类,Java类型体系中最基础的行为也就无法保证,应用程序也将会变得一片混乱。

    参考

    1、周志明,深入理解Java虚拟机:JVM高级特性与最佳实践,机械工业出版社 

  • 相关阅读:
    统计nginx日志里访问次数最多的前十个IP
    while 格式化输出 运算符 字符编码
    Python 软件安装
    Python 基础
    Typora 基础的使用方法
    Django ORM (四) annotate,F,Q 查询
    Django 惰性机制
    Django ORM (三) 查询,删除,更新操作
    Django ORM (二) 增加操作
    Django ORM (一) 创建数据库和模型常用的字段类型参数及Field 重要参数介绍
  • 原文地址:https://www.cnblogs.com/binaway/p/8795116.html
Copyright © 2011-2022 走看看