• 类加载器和双亲委派模型


    什么是类加载器?

    类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作在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高级特性与最佳实践,机械工业出版社 

  • 相关阅读:
    http协议
    三次握手四次挥手的原理
    mmap
    I/O多路复用之poll
    I/O多路转接之select
    自旋锁、文件锁、大内核锁
    网络基础(一)
    线程同步之(信号量)
    进程与线程的简单理解
    内存溢出——程序员必备网站
  • 原文地址:https://www.cnblogs.com/binaway/p/8795116.html
Copyright © 2020-2023  润新知