1. 类的生命周期


JVM类加载_初始化


2. 加载阶段Loading



  • 通过类的全限定名来获取类的二进制字节流

    • 数组类本身不通过类加载器创建,由虚拟机直接创建
    • 数组类的组件类型是引用类型,递归加载过程去加载
    • 数组类的组件类型不是引用类型(int[]),虚拟机把数据与引导类加载器关联

  • 把字节流的静态存储结构,转化成方法区的运行时数据结构
  • 内存中生成对应的Class对象,作为这个类的访问入口(Hotspot放在方法区)



3. 验证阶段



  • 文件格式验证

    • 文件版本是否在当前虚拟机处理范围内等,以保证字节流能被正确存储在方法区

  • 元数据验证

    • 是否有父类;是否非法继承了final类;是否实现了接口方法;是否与父类方法冲突等

  • 字节码验证

    • int类型数据按long类型加载到本地变量表;跳转指令跳转到方法体以外;错误的类型转换等对方法体校验

  • 符号引用验证



3. 准备阶段



  • 为静态属性分配内存,并设置初始值
  • int类型初始化为0,正式的赋值语句在【类构造器】里,即初始化阶段
  • final int会赋真实值


4. 解析阶段



  • 虚拟机将常量池中的符号引用替换为直接引用




5. 初始化阶段



  • 在初始化阶段最重要的事情就是对类变量进行初始化和执行静态块
  • 解释:执行【类构造器】clinit()方法,该方法是编译器自动收集类变量赋值动作和静态块生成的
  • 父类的【类构造器】会先于子类执行;父接口的【类构造器】不会先执行
  • 多线程环境下【类构造器】的执行会加同步锁
  • 对类变量指定初始值有两种方式:1、声明类变量时指定初始值;2、使用静态初始化块为类变量指定初始值






  • 初始化的时机

    • 1)创建类实例的时候,分别有:1、使用new关键字创建实例;2、通过java.lang.reflect包的反射调用;3、通过反序列化方式创建实例。4.Class.forName?
    • 2)调用某个类的静态方法
    • 3)读取或者设置某个类或接口的静态属性(被final修饰的除外)
    • 4)初始化某个类的子类,其父类应该先被初始化。
    • 5)直接使用java.exe命令来运行某个主类(包含main方法的类)。

  • 不会触发类的初始化

    • 通过子类调用父类的静态变量,只初始化父类,不会初始化子类
    • 2、通过数组定义引用类(即定义目标类的数组),不会触发此类的初始化
    • 3、引用常量时,不会触发该类的初始化






public static final String tt = "aaa"; //引用Sup.tt不会触发

public static final String tt; //引用Sup.tt会触发
static { tt = "bbb"; }





6. 类加载器



  • 任何一个类需要和加载它的类加载器一起确立在虚拟机中的唯一性
  • 类加载器

    • 启动类加载器Bootstrap Classloader

      • 是虚拟机的一部分,C++编写(其它都是java编写继承Classloader抽象类)
      • 加载JAVA_HOME/lib下特定文件名的类库(例如rt.jar)到虚拟机内存
      • 无法直接引用。自定义类加载器需要委派给Bootstrap,直接使用null代替即可

    • 扩展类加载器Extention Classloader

      • 由sun.misc.Launcher$ExtClassLoader实现
      • 负责加载JAVA_HOME/lib/ext目录,或者java.ext.dirs指定目录下的所有类库
      • 开发者可直接使用该类加载器

    • 应用类加载器Application Classloader

      • 由sun.misc.Launcher$AppClassLoader实现,也称为系统加载器
      • 程序默认的类加载器,加载classpath上指定的类库


  • 双亲委派模型-Paraents Delegation Model

    • 除了启动类加载器,别的加载器都得有父加载器
    • 工作过程:当一个类加载器收到加载请求,会先让父加载器尝试加载,只有父加载器无法加载时自己才会加载

      • 代码ClassLoader.loadClass()

    • 好处:假如用户自己写了一个java.lang.Object类,就会委派给Bootstrap去加载,保证了所有加载环境得到的是同一个类,否则会出现多个Object导致混乱
    • 自定义类加载器无法加载java.lang开头的类,会跑出异常SecurityException:禁止的包名java.lang
    • 破坏双亲委派 -- 没看