• Android---Class 对象在执行引擎中的初始化过程


    一个 class 文件被加载到内存中的步骤如下图所示:

    装载

     装载是指 Java 虚拟机查找 .class 文件并生成字节流,然后根据字节流创建 java.lang.Class 对象的过程。

    1. ClassLoader 通过一个类的全限定名包名+类名)来查找 .class 文件,并生成二进制字节流。其中 class 字节码文件的来源:1).class 文件;2)jar包,zip包;3)网络的字节流。

    2. 把 .class 文件的各个部分分别解析(parse)为 JVM 内部特定的数据结构,并存储在方法区。JVM 会将这些 .lcass 文件的结果转换为 JVM 内部运行时数据结构。

    3. 在内存中创建一个 java.lang.Class 类型的对象。程序在运行过程中所有对该类的访问都通过这个类对象,也就是这个 Class 类型的类对象是提供给外界访问该类的接口。

    加载时机

    隐式装载:在程序运行过程中,当碰到通过 new 等方式生成对象时,系统会隐式调用 ClassLoader 去装载对应的 class 到内存中。

    显示装载:在编写源代码时,主动调用 Class.forName() 等方法也会进行 class 装载操作。

    链接

    链接过程分为3步:验证、准备、解析

    1. 验证

    目的是为了确保.class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危及虚拟机本身的安全。
    ● 文件格式检验:检验字节流是否符合class文件格式的规范,并且能被当前版本的虚拟机处理
    ● 元数据检验:对字节码描述的信息进行语义分析,以保证其描述的内容符合Java语言规范的要求
    ● 字节码检验:通过数据流和控制流分析,确定程序语义是合法、符合逻辑的
    ● 符号引用检验:可以看作是对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验

    2. 准备

    准备的主要目的是为类中的静态变量分配内存,并为其设置“0值”。

    public static int value = 100;

    准备阶段,JVM 会为 value 分配内存,并将其设置为0,而真正的值100 是在初始化阶段设置。

    public static final int value = 100;

    有 final 关键字修饰的变量会在准备阶段分配内存并设置值为100。

    Java 中基本类型的默认“0值”如下:

    ● 基本类型(int, long, short, char, byte, boolean, float, double)的默认值为0;

    ● 引用类型默认值是 null。

    3. 解析

    解析的任务是把常量池中的符号引用转换为直接引用,也就是具体的内存地址。在这一阶段,JVM 会将常量池中的类、接口名、字段名、方法名等转换为具体的内存地址。

    初始化

    初始化这一阶段是执行类构造器方法的过程,并真正初始化类变量。例如

    public static int value = 100;

    在准备阶段,JVM 会为 value 分配内存,并将其设置为0,而真正的值100 是在初始化阶段设置。

    初始化的时机

    JVM规范中严格规定了class初始化的时机,主要有以下几种情况会触发class的初始化:
    1. 虚拟机启动时,初始化包含main方法的主类
    2. 遇到new指令创建对象实例时,如果目标对象类没有被初始化则进行初始化操作
    3. 当遇到访问静态方法或者静态字段的指令时,如果目标对象类没有被初始化则进行初始化操作
    4. 子类的初始化过程如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化
    5. 使用反射API进行反射调用时,如果类没有进行过初始化则需要先触发其初始化
    6. 第一次调用java.lang.invoke.MethodHandle实例时需要初始化MethodHandle指向方法所在的类

    初始化类变量

    在初始化阶段,只会初始化与类相关的静态赋值语句静态语句,也就是有 static 关键字修饰的信息。没有 static 修饰的语句块在实例化对象的时候才会执行。

    Class 初始化和对象的创建顺序

    面试题:在代码中使用 new 创建一个类的实例对象时,类中的静态代码块、非静态代码块、构造函数之间的执行顺序是怎样的?

    对象的初始化顺序:静态变量/静态代码块 -->  普通代码块 --> 构造函数

    1. 父类静态变量和静态代码块
    2. 子类静态变量和静态代码块
    3. 父类普通成员变量和普通代码块
    4. 父类的构造函数
    5. 子类普通成员变量和普通代码块
    6. 子类的构造函数

    总结
    1. 装载:指查找字节流,并根据此字节流创建类的过程,装载过程成功的标志就是在方法区中成功创建了类所对应的 Class 对象。

    2. 链接:指验证创建的类,并将其解析到 JVM 中使之能够被 JVM 执行。

    3. 初始化:是将标记为 static 的字段进行赋值,并且执行 static 标记的代码语句。

  • 相关阅读:
    QGIS文章一——实现天地图加载
    《架构风清扬-Java面试系列第27讲》Java中如何正确优雅关闭线程?
    idea的macOS Apple Silicon (dmg)版本和macOS (dmg)版本有什么区别
    如何停止一个线程?
    SRM供应商平台哪些好用?
    zblog翻译插件-zblog自动采集翻译插件免费
    BIOMOD2模型、MaxEnt模型物种分布模拟,生物多样性生境模拟,论文写作
    [Polkadot] 波卡链学习笔记
    【ict云赛道备考】华为云介绍
    众和策略:华为汽车概念活跃,圣龙股份斩获12板,华峰超纤涨10%
  • 原文地址:https://blog.csdn.net/qq_44950283/article/details/133675111