java 类的实例化过程,其中的相关顺序 包括有继承的子类等复杂情况,静态成员变量的初始化顺序,这其中jvm在干什么

Java类的实例化过程及初始化顺序

Java类的实例化过程涉及多个步骤,特别是在存在继承关系和静态成员的情况下。下面我将详细解释整个过程,包括JVM在其中的角色。

1. 类加载阶段(JVM的工作)

在实例化一个类之前,JVM首先需要加载这个类:

  1. 加载:JVM查找并加载类的二进制数据(.class文件)

  2. 验证:确保加载的类正确无误,符合JVM规范

  3. 准备:为类的静态变量分配内存,并设置默认初始值(0, null, false等)

  4. 解析:将符号引用转换为直接引用

  5. 初始化:执行类的静态初始化代码和静态变量初始化

2. 实例化过程顺序(包含继承)

当使用new关键字创建对象时,完整的初始化顺序如下:

父类静态成员和静态代码块

  1. 父类的静态变量初始化

  2. 父类的静态代码块(按代码中的顺序执行)

子类静态成员和静态代码块

  1. 子类的静态变量初始化

  2. 子类的静态代码块(按代码中的顺序执行)

父类实例成员和构造代码块

  1. 父类的实例变量初始化

  2. 父类的构造代码块(按代码中的顺序执行)

  3. 父类的构造函数(如果没有显式调用其他构造函数,则调用默认无参构造)

子类实例成员和构造代码块

  1. 子类的实例变量初始化

  2. 子类的构造代码块(按代码中的顺序执行)

  3. 子类的构造函数

3. JVM在实例化过程中的工作

在整个实例化过程中,JVM负责:

  1. 内存分配:为对象和它的实例变量分配堆内存

  2. 初始化默认值:将所有实例变量设置为默认值(0, null, false等)

  3. 方法表设置:为对象设置方法表(用于动态绑定和多态)

  4. 执行初始化代码:按照上述顺序执行各种初始化代码

  5. 构造器链调用:确保父类构造器在子类构造器之前被调用

  6. 处理多态:在运行时确定实际要调用的方法版本

4. 示例代码

class Parent {static {System.out.println("Parent static block");}{System.out.println("Parent instance block");}Parent() {System.out.println("Parent constructor");}
}class Child extends Parent {static {System.out.println("Child static block");}{System.out.println("Child instance block");}Child() {System.out.println("Child constructor");}
}public class Main {public static void main(String[] args) {new Child();}
}

输出顺序:

Parent static block
Child static block
Parent instance block
Parent constructor
Child instance block
Child constructor

5. 特殊情况

  • 如果类中有多个静态变量和静态代码块,它们按照在代码中出现的顺序执行

  • 实例变量和构造代码块也是按照代码中的顺序执行

  • 如果构造函数中显式调用了其他构造函数(this()或super()),则先执行被调用的构造函数

  • 如果父类没有无参构造器,子类必须显式调用父类的某个构造器(super(...))

理解这些初始化顺序对于避免NullPointerException和其他初始化相关的问题非常重要,特别是在复杂的继承层次结构中。

关于 Java 类的实例化过程

✅ 整体顺序正确,但可以补充一些关键细节:

需要修正/补充的点:

  1. 静态初始化(JVM 类加载阶段)

    • 静态变量和静态代码块的初始化顺序 仅发生在类首次被主动使用时(比如 new、访问静态成员、Class.forName() 等),而不是在程序启动时全部加载。

    • 如果类已经被加载过(比如之前已经调用过静态方法),则不会再次执行静态初始化。

  2. 实例初始化

    • final 实例变量 的初始化必须在构造函数完成之前完成,否则编译错误。

    • 如果类没有显式构造函数,JVM 会提供默认无参构造,但如果父类没有无参构造,子类必须显式调用 super(...),否则编译失败。

  3. JVM 的隐含操作

    • 在构造函数真正执行前,JVM 会 隐式初始化所有实例变量为默认值0/null/false),然后才执行显式赋值或初始化块。

    • 如果存在 实例变量直接赋值(如 int x = 5;),这些赋值会在构造代码块之前执行。

示例修正:

class Parent {static { System.out.println("Parent static block"); }{ System.out.println("Parent instance block"); }Parent() { System.out.println("Parent constructor"); }
}class Child extends Parent {static { System.out.println("Child static block"); }{ System.out.println("Child instance block"); }int x = initX(); // 这个会在实例块之后执行吗?❌ 实际在实例块之前!Child() { System.out.println("Child constructor"); }private int initX() { System.out.println("Initializing x"); return 1; }
}public class Main {public static void main(String[] args) {new Child();}
}

实际输出:

Parent static block
Child static block
Parent instance block
Parent constructor
Initializing x  // 变量初始化在实例块之前!
Child instance block
Child constructor

1. final 实例变量必须在构造函数完成前初始化(否则编译错误)

final 实例变量必须在 对象构造完成前 被赋值,且只能赋值一次。有三种方式初始化:

  1. 声明时直接赋值

  2. 在实例初始化块中赋值

  3. 在每个构造函数中赋值

class FinalExample {final int x;          // ❌ 如果不初始化,编译报错final int y = 10;     // ✅ 方式1:声明时赋值final int z;{ z = 20; }           // ✅ 方式2:实例初始化块赋值FinalExample() {x = 30;           // ✅ 方式3:构造函数中赋值}FinalExample(int val) {x = val;         // ✅ 另一个构造函数也必须赋值}
}
错误示例:
class FinalError {final int x;  // ❌ 编译错误:未初始化final变量xFinalError() {// 忘记给x赋值}
}

2. 父类没有无参构造时,子类必须显式调用 super(...)

如果父类 没有无参构造,子类 必须 在构造函数的第一行显式调用 super(...),否则编译失败。

示例代码:
class Parent {Parent(int value) {  // ❗父类只有带参构造,没有默认无参构造System.out.println("Parent constructor: " + value);}
}class Child extends Parent {Child() {super(10);  // ✅ 必须显式调用父类构造,否则编译错误System.out.println("Child constructor");}
}public class Main {public static void main(String[] args) {new Child();}
}
输出:
Parent constructor: 10
Child constructor
错误示例:
class Child extends Parent {Child() {  // ❌ 编译错误:父类Parent中没有默认构造函数System.out.println("Child constructor");}
}

关键总结

  1. final 实例变量

    • 必须且只能赋值一次。

    • 必须在构造完成前初始化(三种方式选其一)。

  2. 构造函数继承规则

    • 如果父类 没有无参构造,子类 必须显式调用 super(...)

    • 如果父类有无参构造,子类可以不写 super()(JVM 会隐式调用)。

这些规则由 Java 语言规范(JLS) 强制约束,编译器会严格检查。

    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/80958.shtml

    如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    Sce2DriveX: 用于场景-到-驾驶学习的通用 MLLM 框架——论文阅读

    《Sce2DriveX: A Generalized MLLM Framework for Scene-to-Drive Learning》2025年2月发表,来自中科院软件所和中科院大学的论文。 端到端自动驾驶直接将原始传感器输入映射到低级车辆控制,是Embodied AI的重要组成部分。尽管在将多模态大语言模型&…

    【题解-Acwing】870. 约数个数

    题目:870. 约数个数 题目描述 给定 n 个正整数 ai,请你输出这些数的乘积的约数个数,答案对 109+7 取模。 输入 第一行包含整数 n。 接下来 n 行,每行包含一个整数 ai。 输出 输出一个整数,表示所给正整数的乘积的约数个数,答案需对 109+7 取模。 数据范围 1 ≤ …

    创龙全志T536全国产(4核A55 ARM+RISC-V+NPU 17路UART)工业开发板硬件说明书

    前 言 本文档主要介绍TLT536-EVM评估板硬件接口资源以及设计注意事项等内容。 T536MX-CXX/T536MX-CEN2处理器的IO电平标准一般为1.8V、3.3V,上拉电源一般不超过3.3V或1.8V,当外接信号电平与IO电平不匹配时,中间需增加电平转换芯片或信号隔离芯片。按键或接口需考虑ESD设计…

    Redis 持久化双雄:RDB 与 AOF 深度解析

    Redis 是一种内存数据库,为了保证数据在服务器重启或故障时不丢失,提供了两种持久化方式:RDB(Redis Database)和 AOF(Append Only File)。以下是它们的详细介绍: 一、RDB 持久化 工…

    数据结构|并查集

    Hello !朋友们,这是我在学习过程中梳理的笔记,以作以后复习回顾,有时略有潦草,一些话是我用自己的话描述的,可能不够准确,还是感谢大家的阅读! 目录 一、并查集Quickfind 二、两种算…

    【GPU 微架构技术】Pending Request Table(PRT)技术详解

    PRT(Pending Request Table)是 GPU 中用于管理 未完成内存请求(outstanding memory requests)的一种硬件结构,旨在高效处理大规模并行线程的内存访问需求。与传统的 MSHR(Miss Status Handling Registers&a…

    远程访问你的家庭NAS服务器:OpenMediaVault内网穿透配置教程

    文章目录 前言1. OMV安装Cpolar工具2. 配置OMV远程访问地址3. 远程访问OMV管理界面4. 固定远程访问地址 前言 在这个数据爆炸的时代,无论是管理家人的照片和视频,还是企业老板处理财务报表和技术文档,高效的数据管理和便捷的文件共享已经变得…

    微服务架构下的熔断与降级:原理、实践与主流框架深度解析

    微服务架构下的熔断与降级:原理、实践与主流框架深度解析 在现代分布式系统中,熔断 (Circuit Breaker) 和 降级 (Degrade) 是保障系统弹性与高可用性的核心机制。本文将系统解析两者的原理、区别与协同方式,并结合主流框架 (Resilience4j、S…

    docker-vllm运行大模型

    vllm镜像下载,国内代理源 vllm/vllm-openai - Docker Image - 毫秒镜像https://1ms.run/r/vllm/vllm-openai 执行下载docker pull docker.1ms.run/vllm/vllm-openai 查看本地镜像 查看镜像 查看镜像 docker images导出镜像 docker save -o E:\docker\ollama.tar …

    基于tabula对pdf中多个excel进行识别并转换成word中的优化(四)

    对上一节进行优化: 1、识别多个excel 2、将表格中的nan替换成空字符串 一、示例中的pdf内容 二、完整代码参考: import tabula import numpy as np from docx import Document from docx.oxml.ns import qn from docx.oxml import OxmlElementdef get_t…

    【10分钟读论文】Power Transmission Line Inspections电力视觉水文

    标题Power Transmission Line Inspections: Methods, Challenges, Current Status and Usage of Unmanned Aerial Systems 2024 评分一颗星 论文《Power Transmission Line Inspections: Methods, Challenges, Current Status and Usage of Unmanned Aerial Systems》的核心内…

    linux安装ragflow

    先安装docker,操作步骤参考文章: Linux安装Docker docker安装完毕,下载ragflow源码: https://github.com/infiniflow/ragflow 下载完成,进入docker文件夹中,修改.env文件,因为默认安装的是sli…

    学习记录:DAY20

    技术探索之旅:YAML配置,依赖注入、控制反转与Java注解 前言 最近有点懒了,太松懈可不行。为了让自己保持学习的动力,我决定将最近的学习内容整理成博客,目标是让未来的自己也能轻松理解。我会尽量以整体记录的方式呈…

    MCP:人工智能时代的HTTP?探索AI通信新标准

    每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

    首版次误区有哪些?与软件测试报告又有什么联系?

    在软件开发与测试领域,"首版次"这一概念关乎软件的版本控制与管理,是确保产品质量和发布节奏的重要环节。首版次,通常是指软件产品第一个对外发布或内部验收的版本号,标志着一次完整开发周期的结束和下一阶段工作的开始…

    Laravel+API 接口

    LaravelAPI 接口 网课连接:BIlibili. 中文文档. 1.RestFul Api编码风格 一、API设计 修改hosts,C:\Windows\System32\drivers\etc\hosts,增加127.0.0.1 api.lv8.com # Laravel 框架 用这个域名来测试(推荐规范) 在…

    MIT6.S081-lab7前置

    MIT6.S081-lab7前置 这部分包含了设备中断和锁的内容 设备中断 之前系统调用的时候提过 usertrap ,而我们的设备中断,比如计时器中断也会在这里执行,我们可以看看具体的逻辑: void usertrap(void) {int which_dev 0;if((r_sst…

    Linux 下编译BusyBox

    一、linux下编译 1.拉取busybox源码 git clone https://github.com/mirror/busybox.git 内容如下 2.配置make,建议在linux下单独开一个终端执行 进入busybox源码目录,使用如下命令 make menuconfig 3.报错 解决办法: 安装ncurses sud…

    Element:Cheack多选勾选效果逻辑判断

    效果展示 取消子级勾选&#xff0c;父级的勾选效果 代码合集 &#xff08;1&#xff09;组件代码 fromlist.cheackType 类型&#xff0c;permissio表示是权限. fromlist:[{id:1,children:[{...}]},...]传递的数据大致结构 <!-- 操作权限 --><template v-if"…

    【3DMax脚本MaxScript开发:创建高效模型虚拟体绑定和材质管理系统,从3DMax到Unreal和Unity引擎_系列第一篇】

    3ds Max 脚本开发 3ds Max 脚本开发&#xff1a;创建高效模型虚拟体绑定和材质管理系统3ds Max 插件制作背景&#xff1a;设计思路一、场景节点收集与过滤废话不多说&#xff0c;直接上完整代码&#xff1a;界面定义与基础设置界面控件创建状态变量核心逻辑函数过滤选项改变事件…