理解java的类生命周期与加载过程

  • 什么是类加载机制
    java文件经过JAVAC编译成class的字节码文件存储在磁盘中。JVM从磁盘中将class文件加载到内存,并对加载的该class文件进行校验,连接,初始化后,形成可以被JVM解析和编译的文件的过程,叫做类加载机制。
  • java的类加载过程,校验、连接、初始化是在程序运行时期间完成的,为java提供极高的灵活性和扩展性。

类生命周期

在这里插入图片描述
类生命周期中
加载、校验、准备、初始化、卸载这五个阶段的执行顺序是确定的,类的加载过程中,必须按找这个五个步骤按部就班的开始。
解析阶段则不一定,可以在初始化阶段之后再进行,这是因为java的动态绑定特性。
《java虚拟机规范》中并没有强制规定在什么情况下开始第一阶段“加载”的执行,这可以交给虚拟机的具体实现来自由把握。但是严格规定了六种情况之下,必须对类进行“初始化”操作。当然,在进行初始化操作之前,加载、校验、准备会在初始化之前开始。

必须对类进行初始化的六中情况

  1. 以下场景如果没有进行初始化,则需要先触发其初始化

    • 使用new关键字实例化对象的时候
    • 读取或者设置一个静态类的字段(被final修饰、已在编译时期就把结果放入常量池的静态字段除外)
    • 调用一个类的静态方法时
  2. 使用java.lang.reflect包对类进行反射调用的时候,如果没有对该类进行初始化,则需要先触发其初始化。

  3. 当初始化一个类的时候,如果没有对父类进行初始化,则需要先对其父类进行初始化。

  4. 当虚拟机启动时,用户要先指定一个执行的主类(main()方法的类),需要先对该主类进行初始化。

  5. 当使用JDK 7新加入的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解
    析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句
    柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。

  6. 当一个接口中定义了JDK 8新加入的默认方法(被default关键字修饰的接口方法)时,如果有
    这个接口的实现类发生了初始化,那该接口要在其之前被初始化。

类加载过程

  1. 加载(Loading)

     	将磁盘中由javac编译成的class文件加载到内存中。 
    

    加载到内存中的class会对应的在内存中开辟两块内存:

    • 一块是将这个class文件加载到内存后存放的区域(JVM将student.class由磁盘加载到内存,是不是得开辟一块空间来存放这个student.class文件呢)
    • 另一块是生成的代表这个类的java.lang.Class对象,并且这个Class对象会指向存储在内存中的那块区域,作为方法区这个类的访问入口。

在这里插入图片描述
Jvm将student.class文件加载到内存中,会开启一块内存用来存放这个student.class,另外还会开辟一块内存用来生成这个Student类的java.lang.Class对象,并且指向用来存储的那块内存。School对象或者Score对象需要访问Student对象的数据,只能通过访问Student的class对象来获取。

  1. 链接(Linking)

    1. 校验(Verification)

       验证从磁盘加载的class文件是否是一个合格的符合class规范的文件。  
       保证这些加载进来的class运行后不会危害jvm本身。
      

      验证的阶段:

      • 文件格式验证

        1.是否以魔数0xCAFEBABE开头;  
        2.主次版本号是否在JVM的接受范围内(低版本的JVM不能运行高版本的java文件)  
        ...
        
      • 元数据验证

        这个阶段是对字节码描述的语义是否符合《java语言规范》里面的要求  
        1.该类是否具有父类(除了java.lang.Object外,所有的类都应该具有父类)  
        2.该类是否继承了不能被允许继承的父类(final修饰的父类不能被继承)  
        3.是否实现了需要被实现的父类方法。  
        ...
        
      • 字节码验证

        第三阶段是整个验证过程中最繁杂的一个阶段。  
        主要是验证程序的语义是合法的、符合逻辑的。  
        1.确保任意时刻操作数栈的数据类型与指令代码序列都能配合工作:  
        在操作栈放了一个int类型的数据,却按照long类型来加载入本地变量。  
        2.确保方法体中的类型转换是有效的:把一个子类对象赋值给父类,这是安全的。但是  
          如果将一个父类对象赋值给子类,这就是不合法的。  
        ...
        
      • 符号引用验证

        最后一个阶段的校验行为发生在虚拟机将符号引用转化为直接引用 的时候,  
        这个转化动作将在连接的第三阶段————解析阶段中发生。  
        符号引用验证可以看作是对类自身以外(常量池中的各种符号引用)的各类信息进行匹配性校验,  
        通俗来说就是,该类是否缺少或者被禁止访问它依赖的某些外部类、方法、字段等资源。
        
    2. 准备(Preparation)

      这一阶段为类变量分配内存以及赋初值
      
      • 类变量:是指被static修饰的变量。
      • 赋初值:是指初始值,而不是程序设置的值。比如:publc static int aa = 9;在这一阶段aa的初始值是0而不是9,将9赋值给aa需要到初始化阶段才会被执行。
      • 这一阶段仅对类变量进行内存分配,而不包括实例变量,实例变量会随对象实例化时一同分配到java堆中。
      • 如果类变量被final修饰,初值为程序设置的值。如:publc static final int bb = 99;这时这一阶段后bb的值为99。
    3. 解析(Resolution)

      解析阶段是将Jvm将常量池内的符号引用转化为直接引用的过程
      
      • 符号引用
        以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时无歧义地能够定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标不一定是加载到虚拟机内存当中的内容。

        emm…有点抽象

        • 符号引用常以CONSTANT_Methodref_info、CONSTANT_Class_info、CONSTANT_Utf8_info等等类型的常量出现,每种类型都有自己特定的意义,比如:“CONSTANT_Utf8_info”代表UTF-8的字符串,而“CONSTANT_Methodref_info”代表类中的方法。JVM中有17中常量类型,每种都有自己的特定含义,是比较负责的,这里不具体展示。

        • 符号引用属于编译原理方面的概念。jvm在加载class文件的时候是进行动态链接的,也就是说在class中不会保存各个方法、字段在内存中的布局信息(也就是说并不知道引用的实际地址),因为各种虚拟机实现的内存布局信息可能各不相同,但是接收到的符号引用是一致的,因为符号引用的字面量形式明确定义在java虚拟机规范的class文件格式中。比如:Student类中有个getName方法,在编译时使用“CONSTANT_Methodref_info”来描述这个getName方法。

      • 直接引用
        直接引用是和虚拟机的布局相关的,同一个符号引用在不同的虚拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经被加载入内存中了。

        直接引用可能是:

        • 直接指向目标的指针(比如,指向“类型”【Class对象】、类变量、类方法的直接引用可能是指向方法区的指针)
        • 相对偏移量(比如,指向实例变量、实例方法的直接引用都是偏移量)
        • 一个能间接定位到目标的句柄
  2. 初始化(Initialization)

     类的初始化阶段是类加载过程的最后一步,  
     这个阶段java虚拟机才真正开始执行类中编写的java程序代码。  
     在准备阶段,已经对类变量进行了内存分配与赋默认值。  
     而初始化阶段会将程序代码设置的值赋给对应的类变量。
    

    比如:public static int aa = 99; 在准备阶段aa = 0;在初始化阶段aa = 99;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值