面试题:类加载子系统

类加载器子系统的作用

类加载器子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识,ClassLoader只负责加载class文件,加载的类信息存放在方法区中,除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量。

类加载过程

  • 加载
    • 通过一个类的全限名来获取定义此类的二进制节流。(实现这个代码模块就是类加载器)
    • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
    • 在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口。
  • 验证
    • 目的在于确保class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全。
    • 文件格式验证,元数据验证,字节码验证,符号引用验证。
  • 准备
    • 为类变量分配内存并设置类变量的默认初始化,即零值。
    • 这里不包含用final修饰的static,因为final在编译的时候就会分配了,准备阶段会显式初始化。
    • 这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到java堆中。
  • 解析
    • 将常量池内的符号引用转化为直接引用的过程,解析操作往往是伴随着JVM在执行完初始化后在执行,主要针对类或接口字段,类方法,接口方法,方法类型。
  • 初始化
    • 初始化就是执行类构造器方法的过程,不需要定义,java编译器自动收集类的所有类变量的赋值操作和静态代码块中的语句合并来,而且是按语句在源文件中出现的顺序执行。如果一个类中没有对静态变量赋值也没有静态语句块,那么编译器可以不为这个类生成()方法。

类加载器分类

①、启动类加载器(Bootstrap ClassLoader)

  • 这个类加载使用C/C++语言实现的,嵌套在JVM内部。
  • 它用来加载java的核心库,用于提供JVM自身需要的类。
  • 并不继承自Java.lang.ClassLoader,没有父加载器。
  • 出于安全考虑,Bootstrap启动类加载器只加载包名为java,javax,sun开头的类。

②、扩展类加载器(Extension ClassLoader)

  • java语言编写,由 sun.misc.Launcher$ExtClassLoader 实现
  • 父类加载器为启动类加载器
  • 负责加载<JAVA_HOME>/lib/ext 目录中的,或者被 java.ext.dirs 系统变量所指定的路径中的所有类库。开发者可以直接使用扩展类加载器。

③、应用程序类加载器(Application ClassLoader)

  • sun.misc.Launcher$AppClassLoader 实现
  • 父亲类加载器为扩展类加载器
  • 如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
  • 由于这个类加载器是 ClassLoader.getSystemClassLoader() 方法的返回值,所以一般也称它为系统类加载器。

④、用户自定义类加载器

  • 用来隔离加载类,修改类加载方式,扩展加载源,防止源码泄漏。

双亲委派机制

  • 概念:java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。java虚拟机采用的是双亲委派机制,即把请求由父类处理,它是一种任务委派模式。
  • 工作原理
    • 如果一个类加载收到类加载请求,它并不会自己先去加载,而是把这个请求委托给父亲的类加载器执行。
    • 如果父亲还存在父亲加载器,则进一步向上委托,依次递归,请求最终达到顶层的启动类加载器。
    • 如果父亲类加载器可以完成,就成功返回,如果无法完成,子类加载器才会自己加载。
  • 优势
    • 避免类的重复加载
    • 保护程序安全,防止核心API被随意修改
原文地址:https://www.cnblogs.com/dalianpai/p/14247719.html