【Java 】Java 类加载和类加载器

前言

Java 的类加载阶段分为:加载、链接、初始化,而链接的过程中包括:验证、准备、解析。

一、加载

将类的字节码载入方法区中,内部采用 C++ 的 instanceKclass 描述 Java 类

instanceKclass 的重要字段:

  • _java_mirror:Java 类镜像,存放类对象的地址,例如对于 String,存放的就是String.class
  • _super:即父类
  • _methods:即方法
  • _constants:即常量池
  • _class_loader:类加载器
  • _vtable:虚方法表
  • _itable:接口方法表

在这里插入图片描述

二、链接

链接阶段包括验证、准备、初始化三个部分

验证

验证类是否符合 JVM 规范,进行安全性检查,例如:检查 Java 文件的魔数

准备

为 static 变量分配地址空间,设置默认值

  • static 变量分配空间和赋值是两个步骤,分配空间是在准备阶段完成,而赋值是在初始化阶段完成;
  • 若 static 变量是 final 类型的,且变量类型为基本数据类型或者字符串对象,则在准备阶段进行赋值;
  • 若 static 变量是 final 类型的,且变量类型为引用对象,则仍在初始化阶段进行赋值;

解析

将常量池中的符号引用解析为直接引用

三、初始化

初始化调用 ()v,即执行类的构造方法,代码块等,虚拟机会保证这个类的线程安全

发生的时机

概括的说,类的初始化是懒惰的

  • main 方法所在的类,总会被首先初始化;
  • 首次访问类的静态变量或者静态方法,因为这些变量不是 final 的,会在类的初始化阶段进行赋值;
  • 子类初始化,会引起父类的初始化;
  • 子类方法父类的静态变量,会导致父类的初始化;
  • Class.forName;
  • new 会导致初始化;

不会触发类的初始化

  • 访问类的 static final 静态变量(基本类型和字符串),不会被初始化,因为这些变量的赋值是在准备阶段;
  • 类对象.class 不会触发类的初始化;
  • 创建该类的数组不会触发初始化;
  • 类加载器的 loadClass 方法;
  • Class.forName 的参数 2 为 false 时

四、类加载器

以 JDK8 为例

名称 加载哪里的类 说明
Bootstrap ClassLoader JAVA_HOME/jre/lib 无法直接访问
Extension ClassLoader JAVA_HOME/jre/lib/ext 上级为 Bootstrap ClassLoader,访问为 null
Application ClassLoader classpath 上级为 Extension ClassLoader
自定义类加载器 自定义上级 为 Application ClassLoader

类加载器的作用:加载类的二进制字节码

双亲委派模式

双亲委派模式是一种Java类加载机制,它定义了一种层次化的父子关系,由父类加载器向下委派请求,直到找到合适的类加载器为止。

  • 首先会检查缓存,查找该加载器是否已经加载过这个类了,如果没有就去父类的加载器中去寻找;
  • 如果缓存中没有找到,就会自顶而下用的类加载器去创建该类;
  • 最终返回该类即可;
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 {
                        // 向 Bootstrap 类加载器中找
                        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();
                    // 调用 findClass 去创建类
                    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;
        }
    }

猜你喜欢

转载自blog.csdn.net/u011397981/article/details/130426900