类加载机制

2021-02-02  本文已影响0人  laowangv2

一、类加载的作用

把class文件中的类加载到虚拟机中。什么时候加载呢?触发时机包括以下几种:

  1. 使用静态字段或静态方法,包括new的时候;
  2. 使用java.lang.reflect包的方法对类进行反射调用时;
  3. 初始化一个类时,首先确保初始化其父类;
  4. 虚拟机启动时,加载主类;
  5. 使用动态语言支持时

二、类加载的流程

  1. 加载
    获取二进制字节流,转换成方法区的运行时数据结构,在内存生成一个class对象
  2. 链接
    • 验证
    • 准备
      分配内存,赋初始值
    • 解析
      符号引用替换成直接引用
  3. 初始化
    执行<clinit>()
  4. 使用
  5. 卸载
    需要:所有对象被gc,类对象没有被引用,类加载器被gc

三、类加载模型

双亲委派模型,先给parent load,load不到才会自己load

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

使用这种模型的意义是:

  1. 防止混乱,避免同一个类被各种加载
  2. 保证虚拟机的安全,自己写一个java.开头的类自己加载,会抛出SecurityException

四、类加载器

  1. BootstrapClassLoader
    c++实现,虚拟机的一部分,负责加载运行时需要的核心类库。例如存放在$JAVA_HOME/lib中并且能被虚拟机识别的类(如rt.jar包中的java.开头的类)
  2. ExtClassLoader
    加载$JAVA_HOME/lib/ext中的jar包,实现在sun.misc.Launcher中,他的parent是null,代表BootstrapClassLoader
  3. AppClassLoader
    加载用户路径(ClassPath)上指定的类库,也就是用户实现的类。同样实现在sun.misc.Launcher中,他的parent是ExtClassLoader

五、一些著名的例子

  1. 线程上下文加载器
    起因是例如JNDI服务这样的服务接口作为java标准服务是由BootstrapClassLoader加载的,而其实现由独立厂商提供(SPI,Service Provider Interface)放在classpath下,BootstrapClassLoader无法加载,所以只好使用线程上下文加载器开个后门,默认为AppClassLoader
上一篇下一篇

猜你喜欢

热点阅读