Java类加载初始化的过程及顺序

下面我将详细讲解Java类加载初始化的过程及顺序。

Java类加载初始化的过程

Java的类加载过程一般分为三个部分:类加载、链接和初始化。其中类的加载是指将类的.class文件读入内存,并将其转化成方法区中的运行时数据结构;链接是将类的常量池中的符号引用转化成直接引用的过程,然后进行内存地址的检验,最后完成方法表的预备工作;初始化则是对类的静态变量进行初始化的操作,JVM提供了五种初始化方式。

具体来说,Java类加载初始化的过程如下:

  1. 加载:这是类加载的第一个阶段,在该阶段,类加载器会从本地文件系统或者网络中查找类的字节码文件,并将其读入到JVM中的内存中。当然,在加载的过程中可能会出现各种各样的问题,如类找不到、类格式不正确、访问权限等。
  2. 链接:
  3. 校验:在这个阶段,JVM会对类进行校验,来确保它的字节码是合法的、符合Java虚拟机规范的。该阶段主要是检查字节码文件是否符合规范的内容。如果字节码文件存在错误,那么会抛出java.lang.VerifyError错误。
  4. 准备:在该阶段,JVM会为类信息在内存中分配空间,并且设置类变量的默认值(0、false、null等)。
  5. 解析:在此阶段,JVM会将符号引用替换为直接应用,也就是将常量池中的Class符号转为对应的直接引用。这个阶段可能会归并(合并)一些类或者接口,也可能导致一些类或接口没能被加载,从而抛出java.lang.NoClassDefFoundErrorjava.lang.ClassNotFoundException

  6. 初始化:这是类加载的最后一个阶段,在此阶段JVM必须保证所有静态变量在进行首次访问之前都已经被正确地初始化。JVM定义了五种初始化方式,包含:静态变量赋值、静态代码块赋值、延迟加载、粒度控制、progressive。

类初始化过程中,并不是所有的类都会被初始化。只有在以下情况下类才会被初始化:

  • 创建类的实例
  • 调用类的静态方法
  • 访问类的静态变量
  • 使用反射方式强制创建某个类或接口对应的Class对象,且该类或接口还没有被初始化
  • 初始化某个类或接口的子类。

接下来,我举两个例子来说明Java类加载初始化的过程和顺序。

示例一

我们来看一个简单的Java类SimpleClass,其代码如下:

public class SimpleClass {
    static {
        System.out.println("Static initialization block");
    }

    public static void main(String[] args) {
        System.out.println("Main method");
    }
}

在执行SimpleClass.main方法之前,这个类会被加载、链接和初始化,我们来逐步分析运行结果:

  1. 加载:在运行Java程序时,JVM会查找符号引用,当发现需要加载类时,会调用类加载器来进行加载。在该例中,类的加载通过系统类加载器(AppClassLoader)完成。
  2. 链接
  3. 校验:在该阶段,JVM会校验字节码文件,是否符合规范、正确性等。该阶段的输出为: Static initialization block
  4. 准备:在该阶段,会为类变量在内存中分配空间,并设置默认值。在该例中,在符号表中发现了类的静态变量,被初始化为0或null。
  5. 解析:在该阶段,JVM会将符号引用转换为直接引用。这里并没有符号引用需要转换,所以跳过这个步骤。

  6. 初始化:在该阶段,执行类的静态初始化。在SimpleClass中,静态代码块将被执行,并打印Static initialization block

这样上述SimpleClass类的类加载初始化过程便完整地走完了。

示例二

下面我们再来看一下更复杂一些的类的初始化顺序。下面先给出Parent父类和Child子类的定义:

class Parent {
    public static int A = 1;

    static {
        A = 2;
    }
}

class Child extends Parent {
    public static int B = A;

    public static void main(String[] args) {
        System.out.println(B);
    }
}

那么我们再分析Child类的初始化过程:

  1. 加载:Child类的加载器是系统类加载器(AppClassLoader),因为该类是通过main方法启动的。
  2. 链接:
  3. 校验:此阶段完成后执行Parent类的初始化。Parent的初始化之后的特征是子类可以使用父类的静态属性,在这个例子中执行后A的值修改为2。
  4. 准备:在该阶段,会为类变量在内存中分配空间,并设置默认值。准备阶段结束后,静态变量的值符合程序员的设定,即A=2B=0
  5. 解析:在该阶段,JVM会将符号引用转为直接引用。在这个例子中,没有需要转化的引用需要解析。

  6. 初始化。

  7. 类初始化时会初始化类中的父类
  8. 父类的静态代码块(static block)先于子类执行(源码中Parent的静态部分先于Child),且只会执行一次。
  9. 接着执行子类中的静态代码块(此处没有子类实现)
  10. 最后执行子类自身的main方法
  11. 整个过程中只执行了一次输出,最终的输出结果为:2

所以,通过上面这两个例子,我们可以看出Java类加载初始化的过程及顺序,即先加载,再链接,最后初始化。在初始化期间,首先执行父类初始化,接着执行子类的静态初始化块和静态变量初始化,最后执行子类的主方法。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java类加载初始化的过程及顺序 - Python技术站

(0)
上一篇 2023年6月20日
下一篇 2023年6月20日

相关文章

  • 浅谈pycharm使用及设置方法

    浅谈PyCharm使用及设置方法 PyCharm是一款非常流行的Python集成开发环境,拥有强大、智能的代码编辑、调试、测试和优化功能,可以大大提高Python程序开发效率。本文将介绍PyCharm的基本使用及设置方法。 安装和环境配置 在官网(https://www.jetbrains.com/pycharm/)下载相应版本的PyCharm,并安装到指定…

    other 2023年6月26日
    00
  • Windows10在文件资源管理器中显示/隐藏文件扩展名(后缀名)

    Windows 10文件资源管理器中显示/隐藏文件扩展名(后缀名)攻略 在Windows 10的文件资源管理器中,你可以选择显示或隐藏文件的扩展名(也称为后缀名)。下面是详细的攻略,包含两个示例说明。 显示文件扩展名 要在文件资源管理器中显示文件扩展名,请按照以下步骤进行操作: 打开文件资源管理器。你可以通过按下Win + E键组合来快速打开它。 在文件资源…

    other 2023年8月5日
    00
  • Android中ADB命令用法大结局

    Android中ADB命令用法大结局 ADB(Android Debug Bridge)是Android开发工具包(SDK)中的一个命令行工具,用于与连接的Android设备进行通信和调试。以下是ADB的常见用法及示例说明: 安装应用程序: adb install app.apk 该命令用于将应用程序安装到连接的Android设备上。 卸载应用程序: adb…

    other 2023年10月13日
    00
  • 深入理解Java中观察者模式与委托的对比

    本篇攻略旨在对比Java中观察者模式与委托模式的差异,深入理解它们的作用及使用方法。 一、观察者模式 1. 模式概述 观察者模式是一种设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象状态发生变化时,会通知所有观察者,使它们能够自动更新。 2. 示例说明 下面是一个简单的示例,来演示观察者模式的实现过程。 // 主题接…

    other 2023年6月26日
    00
  • Visio怎么调出开发者选项?

    想要在Visio中调出开发者选项,需要经过以下步骤: 在Visio中打开“文件”菜单,并在菜单中选择“选项”; 在弹出的“选项”对话框中,找到“常规”选项卡,并向下滚动至底部; 在“常规”选项卡的底部,选中“显示开发人员选项卡”复选框; 点击“确定”按钮即可完成设置。 在Visio中开启开发者选项后,在菜单中将会多出一个选项卡,名为“开发人员”。在这个选项卡…

    other 2023年6月26日
    00
  • Vue 技巧之控制父类的 slot

    下面是关于“Vue 技巧之控制父类的 slot”的完整攻略: 1. 简介 在Vue中,slot是一种分发内容到组件的机制,可以在组件内定义一个或多个slot,并且在组件外部通过slot元素来填充这些slot。但有时候需要控制父组件中某一个具体slot的内容,这个时候就需要用到控制父组件的slot的技巧。 2. 如何控制父类的 slot 要控制父类的slot,…

    other 2023年6月27日
    00
  • 浅谈Spring IoC容器的依赖注入原理

    标题: 浅谈Spring IoC容器的依赖注入原理 简介:Spring框架中的IoC容器使用依赖注入(Dependency Injection, DI)的方式构建对象之间的关系。本文将介绍Spring IoC容器的依赖注入原理,包括依赖注入的方式、原理等,并通过示例说明。 正文: 依赖注入的方式 Spring IoC容器中有三种常见的依赖注入方式,分别是构造…

    other 2023年6月27日
    00
  • React更新渲染原理深入分析

    React是一款非常流行的JavaScript库,它具有高效的更新和渲染机制。在React中,当数据发生变化时,React会使用虚拟DOM(Virtual DOM)来计算需要更新的变化,然后将这些变化应用到实际的DOM中。在这个过程中,React使用了许多技术和算法来优化渲染性能。下面,我们将详细讲解React的更新和渲染原理。 React的更新原理 Rea…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部