完整的类在JVM中的生命周期详解
首先给出一个示例代码:
示例的目标是展示一个多功能的类结构,包含继承、接口实现、静态成员、本地方法、线程安全等特性,同时模拟一个简单的“计算器”场景,计算并管理数字。(尽量将所有的 Java 组件和关键字都给出,完整给出全面的生命周期)
示例代码及其作用
这个示例实现了一个计算器类 Calculator,它继承自一个抽象父类 BaseCalculator,并实现了一个接口 Operable。它包含:
- 静态变量和方法来跟踪计算次数。
- 本地方法(假设由 C/C++ 实现)来执行特殊计算。
- 同步方法确保多线程安全。
- 嵌套类和枚举用于扩展功能。
- 子类
AdvancedCalculator进一步扩展功能。
以下是带详细注释的完整代码:
package com.example;// 抽象父类,提供基础计算功能
abstract class BaseCalculator {// 受保护的实例变量,表示基础值protected int baseValue = 10;// 抽象方法,要求子类实现具体的计算逻辑abstract int calculateBase(int input);// 普通方法,显示基础值void displayBase() {System.out.println("基础值: " + baseValue);}
}// 接口,定义可操作的计算行为
interface Operable {// 接口方法,执行加法操作int add(int a, int b);
}// 主类:计算器类,继承 BaseCalculator 并实现 Operable 接口
public class Calculator extends BaseCalculator implements Operable {// 静态常量,记录最大允许的计算次数public static final int MAX_CALCULATIONS = 100;// 静态变量,跟踪全局计算次数private static int calculationCount = 0;// 实例变量,表示当前计算结果,volatile 确保线程可见性private volatile int currentResult = 0;// transient 变量,不会序列化,用于临时存储数据private transient String tempLog = "Calculation started";// 静态初始化块,在类加载时执行一次static {System.out.println("已加载Calculator类。最大允许的计算次数: " + MAX_CALCULATIONS);}// 实例初始化块,每次创建对象时执行{System.out.println("新建Calculator实例。");calculationCount++; // 增加计算次数}// 构造方法,初始化当前结果public Calculator(int initialValue) {super(); // 调用父类构造方法this.currentResult = initialValue;}// 静态方法,返回当前的计算次数public static int getCalculationCount() {return calculationCount;}// 本地方法,假设由 C/C++ 实现,用于特殊计算(这里仅声明)public native int specialCalculation(int input);// 重写抽象方法,计算基于 baseValue 的结果@Overrideint calculateBase(int input) {return baseValue + input;}// 实现接口方法,执行加法操作@Overridepublic int add(int a, int b) {currentResult = a + b;return currentResult;}// 同步方法,确保多线程环境下安全更新结果public synchronized void multiply(int factor) {currentResult *= factor;System.out.println("乘法结果: " + currentResult);}// 获取当前结果的方法public int getCurrentResult() {return currentResult;}// 嵌套静态类,用于日志记录static class CalculationLogger {// 日志记录方法void log(String message) {System.out.println("Log: " + message);}}// 嵌套枚举,表示计算类型enum OperationType {ADD, MULTIPLY, SPECIAL}// 主方法,测试计算器功能public static void main(String[] args) {// 创建计算器实例Calculator calc = new Calculator(5);// 测试继承的父类方法calc.displayBase();// 测试抽象方法实现System.out.println("基础计算结果: " + calc.calculateBase(20));// 测试接口方法System.out.println("加法结果: " + calc.add(10, 15));// 测试同步方法calc.multiply(2);// 测试静态方法System.out.println("总计算次数: " + Calculator.getCalculationCount());// 测试嵌套类CalculationLogger logger = new CalculationLogger();logger.log("Calculation completed");// 测试枚举OperationType op = OperationType.ADD;System.out.println("操作类型: " + op);// 检查实例类型if (calc instanceof Calculator) {System.out.println("实例是计算器");}}
}// 子类:高级计算器,扩展 Calculator 的功能
class AdvancedCalculator extends Calculator {// 子类构造方法public AdvancedCalculator(int initialValue) {super(initialValue);}// 子类新增方法,计算平方public int square() {int result = getCurrentResult() * getCurrentResult();System.out.println("平方的结果: " + result);return result;}
}
代码作用和功能说明
-
类结构和继承:
BaseCalculator是一个抽象父类,提供基础值和方法,模拟计算器的基本功能。Calculator继承BaseCalculator,并实现Operable接口,提供加法等操作。AdvancedCalculator是Calculator的子类,增加了平方计算功能。
-
静态成员:
MAX_CALCULATIONS是静态常量,限制计算次数(示例中未强制执行,仅展示概念)。calculationCount是静态变量,记录创建的计算器实例数。getCalculationCount()是静态方法,提供全局访问。
-
本地方法:
specialCalculation()使用native关键字,假设由本地代码实现特殊计算(实际需要 JNI 实现)。
-
线程安全:
multiply()使用synchronized确保多线程环境下安全更新currentResult。volatile修饰currentResult,保证线程间可见性。
-
嵌套类和枚举:
CalculationLogger是静态嵌套类,用于记录计算日志。OperationType是枚举,定义支持的操作类型。
-
功能实现:
- 支持加法(
add)、乘法(multiply)、平方(square)等计算。 - 提供结果查询(
getCurrentResult)和计算次数统计(getCalculationCount)。 - 通过
main方法测试所有功能。
- 支持加法(
输出示例
运行 main 方法的输出(specialCalculation 未实现):
已加载Calculator类。最大允许的计算次数:100
新建Calculator实例。
基础值:10
基础计算结果:30
加法结果:25
乘法结果:50
总计算次数:1
Log: Calculation completed
操作类型: ADD
实例是计算器
下面详细分析 Java 8 的环境下,上面 Calculator 类从创建到被垃圾回收(GC)销毁的完整流程,涵盖 PC 寄存器、Java 虚拟机栈、Java 堆、方法区、运行时常量池和本地方法栈六个关键部分。我会结合 JVM 的运行时数据区,逐步说明每个阶段的内存分配和回收过程,并尽量贴近底层实现(基于 HotSpot JVM 的典型行为)。
1. 类的加载与初始化(方法区和运行时常量池)
流程概述
在 Calculator 类首次使用(如 Calculator calc = new Calculator(5);)时,JVM 会通过类加载器加载该类及其相关类(BaseCalculator, Operable, AdvancedCalculator 等)。这涉及到方法区和运行时常量池的初始化。
底层原理
-
类加载:
- JVM 使用类加载器(如
AppClassLoader)加载Calculator.class文件。 - 类文件被解析后,JVM 在方法区(Java 8 中为 Metaspace)分配内存,存储类的元数据,包括:
- 类名(
com.example.Calculator) - 父类(
BaseCalculator) - 接口(
Operable) - 字段信息(
MAX_CALCULATIONS,calculationCount等) - 方法表(
add,multiply,specialCalculation等) - 字节码(每个方法的指令序列)。
- 类名(
- JVM 使用类加载器(如
-
运行时常量池:
- 方法区中的一部分逻辑区域为运行时常量池(Runtime Constant Pool),存储类文件中
constant_pool表的运行时表示。 - 例如,
MAX_CALCULATIONS = 100的值 100、字符串"已加载Calculator类..."、方法引用(如System.out.println)等都被放入常量池。 - 在 HotSpot JVM 中,运行时常量池的实现依赖于 Metaspace 中的
ConstantPool对象。
- 方法区中的一部分逻辑区域为运行时常量池(Runtime Constant Pool),存储类文件中
-
静态初始化:
- 类加载完成后,JVM 执行
<clinit>方法(类初始化方法),运行静态初始化块:static {System.out.println("已加载Calculator类。最大允许的计算次数: " + MAX_CALCULATIONS); } - 这会在方法区中为
calculationCount分配内存并初始化为 0,并在 Java 堆中分配字符串对象(常量池引用)。
- 类加载完成后,JVM 执行
源代码层面
- HotSpot JVM 的
InstanceKlass类表示方法区中的类元数据。 ConstantPool对象管理运行时常量池,存储符号引用(如字段和方法的CONSTANT_Fieldref_info)。
2. 对象创建(Java 堆和 Java 虚拟机栈)
流程概述
当执行 Calculator calc = new Calculator(5); 时,JVM 创建 Calculator 对象实例,并分配栈帧来执行构造方法。
底层原理
-
Java 堆分配:
- JVM 在堆的年轻代(Young Generation)中的 Eden 区为
Calculator对象分配内存。 - 对象包含实例字段:
baseValue(继承自BaseCalculator)currentResulttempLog
- 对象头(Object Header)包含元数据,如指向方法区中
Calculator类元信息的指针(klass指针)。
- JVM 在堆的年轻代(Young Generation)中的 Eden 区为
-
Java 虚拟机栈:
- 为调用
Calculator(int)构造方法,JVM 在当前线程的栈中推送一个新的栈帧(Frame)。 - 栈帧结构:
- 局部变量表:存储
this(对象引用)和参数initialValue。 - 操作数栈:用于计算(如
this.currentResult = initialValue)。 - 常量池引用:指向运行时常量池中构造方法的相关条目。
- 局部变量表:存储
- 执行流程:
super();调用BaseCalculator的构造方法,分配一个父类栈帧。this.currentResult = initialValue;将 5 存入堆中的对象字段。- 实例初始化块
{}执行,更新calculationCount。
- 为调用
-
PC 寄存器:
- PC(Program Counter)寄存器记录当前线程正在执行的字节码指令地址。
- 例如,在构造方法中,PC 指向
invokespecial(调用super())或putfield(设置currentResult)指令。
源代码层面
- HotSpot 的
oopDesc表示堆中的对象,markOop是对象头。 frame类管理栈帧,interpreter模块执行字节码。
3. 方法调用(Java 虚拟机栈和本地方法栈)
流程概述
执行 calc.add(10, 15); 和 calc.specialCalculation(20); 时,JVM 分别调用普通方法和本地方法。
底层原理
-
普通方法调用(Java 虚拟机栈):
- 为
add(int, int)创建栈帧:- 局部变量表:
this、a(10)、b(15)。 - 操作数栈:计算
a + b,结果存入currentResult。
- 局部变量表:
- PC 寄存器更新为
add方法的字节码地址。 - 方法返回后,栈帧弹出。
- 为
-
本地方法调用(本地方法栈):
- 调用
specialCalculation(int)时,JVM 使用 Java Native Interface(JNI)。 - 在本地方法栈(Native Method Stack)分配栈帧,存储 JNI 调用参数。
- PC 寄存器值未定义(本地方法不由 JVM 解释执行)。
- JNI 调用本地库(如
.dll或.so文件),假设返回结果。
- 调用
-
同步方法(Java 虚拟机栈):
- 调用
multiply(2)时,栈帧包含同步锁信息。 - JVM 使用对象头的监视器(Monitor)实现
synchronized,确保线程安全。
- 调用
源代码层面
InterpreterRuntime::resolve_invoke解析方法调用。jni.h和JVM_ENTRY宏处理本地方法栈。
4. 对象使用(Java 堆和方法区交互)
流程概述
对象 calc 被使用时,JVM 通过堆和方法区的协作执行逻辑。
底层原理
- 堆中的对象:
currentResult更新为 25(add)、50(multiply)。tempLog指向堆中的字符串对象(若非常量池引用)。
- 方法区:
- 方法字节码从方法区加载到栈帧执行。
- 嵌套类
CalculationLogger和枚举OperationType的元数据也在方法区。
5. 垃圾回收(GC)过程(Java 堆)
流程概述
当 calc 不再被引用(如 calc = null; 或离开作用域),JVM 的垃圾回收器(GC)回收其内存。
底层原理
-
可达性分析:
- GC 从根集(GC Roots)开始标记:
- 栈中的局部变量(如
calc)。 - 方法区中的静态变量(如
calculationCount)。
- 栈中的局部变量(如
- 若
calc无引用,则标记为不可达。
- GC 从根集(GC Roots)开始标记:
-
年轻代回收(Minor GC):
calc在 Eden 区创建,若仍存活,可能晋升到 Survivor 区。- Minor GC 使用复制算法(Copying Algorithm):
- 将 Survivor 中的存活对象移动到另一个 Survivor 或老年代。
- 清空 Eden 和当前 Survivor。
-
老年代回收(Major GC):
- 若
calc存活多次 Minor GC,晋升到老年代(Tenured Generation)。 - 使用标记-清除(Mark-Sweep)或标记-整理(Mark-Compact)算法:
- 标记存活对象。
- 清除不可达对象(如
calc),回收内存。
- 若
-
Metaspace(方法区)回收:
- 若
Calculator类不再被使用(无实例且类加载器可回收),Metaspace 中的元数据和常量池条目被回收。 - Java 8 中 Metaspace 使用本地内存,受
-XX:MaxMetaspaceSize控制。
- 若
源代码层面
GenCollectedHeap管理堆的分代。G1CollectedHeap(默认 GC)实现分代回收。MetaspaceUtils处理 Metaspace 回收。
6. 完整流程总结
- 方法区和常量池:类加载,元数据和常量存储。
- Java 堆:对象在 Eden 区创建,字段存储实例数据。
- Java 虚拟机栈:栈帧执行构造方法和普通方法。
- PC 寄存器:跟踪指令地址。
- 本地方法栈:执行
native方法。 - GC 销毁:对象不可达后,Minor/Major GC 回收堆内存,Metaspace 回收类元数据。
相关文章:
完整的类在JVM中的生命周期详解
首先给出一个示例代码: 示例的目标是展示一个多功能的类结构,包含继承、接口实现、静态成员、本地方法、线程安全等特性,同时模拟一个简单的“计算器”场景,计算并管理数字。(尽量将所有的 Java 组件和关键字都给出&am…...
Flutter中常用命令
1.检测flutter运行环境 flutter doctor 2.升级flutter flutter upgrade 3.查看flutter 版本 flutter --version 4.查看连接的设备 flutter devices 5.运行flutter项目 flutter run 或者在vscode中按FnF5 6.打包 flutter build apk //默认打release包 7.开…...
C#里使用libxl的数字格式
由于EXCEL里可以表示不同的数字格式, 比如表示货币数字时,与表示普通序号的数字就不一样。 还有科学计算表示的数字使用小数点位数与普通货币也不一样。 如下所示: 要使用这些格式, 下面创建一个例子来演示保存这些数字格式: private void button11_Click(object send…...
c#难点整理2
1.对象池的使用 就是先定义一系列的对象,用一个,调一个。 public class ObjectPool<T> where T : new(){private Queue<T> pool; // 用于存储对象的队列private int maxSize; // 对象池的最大容量// 构造函数public ObjectPool(int maxSi…...
android adjust 卸载与重装监测
想要洞察应用内用户的留存率,可以通过Adjust 的卸载与重装进行监测 名词解释: 卸载:集成完成后,卸载应用,安装状态为:卸载 重装:如果应用已经卸载,但一段时间后又进行安装,则会被视为重装。 📢📢📢:adjust 文件中说到24 小时后,可以再 adjust 控制台看安装…...
自然语言处理(5)—— 中文分词
中文分词的基本原理及实现 1. 什么是词2. 基本原理3. 发展趋势:多数场景无需显式分词 信息处理的目标是使用计算机能够理解和产生自然语言。而自然语言理解和产生的前提是对语言能够做出全面的解析。 汉语词汇是语言中能够独立运用的最小的语言单位,是语…...
解锁物联网高效开发,Synaptics SYN43756E Wi-Fi 6E 芯片登场
Synaptics 的 SYN43756E 芯片是一款高性能的 Wi-Fi 6E 支持 11a/b/g/n/ac/ax 的物联网(IoT)SoC,具备多项先进特性,适用于多种应用场景,以下是其主要优势: 1. 广泛的应用场景 智慧家庭:支持多种…...
C++和标准库速成(十二)——练习
目录 练习1.1题目答案 练习1.2题目答案 练习1.3题目答案 练习1.4题目答案 练习1.5题目答案 练习1.6题目答案 参考 练习1.1 题目 修改下面的Employee结构体,将其放在一个名为HR的名称空间中。你必须对main()中的代码进行那些修改才能使用此新实现?此外&a…...
DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能📚页面效果📚指令输入�…...
5、linux c 线程 - 上
【四】线程 1. 线程的创建 #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*routine)(void *), void *arg); pthread_t *thread:指向线程标识符的指针,用于存储新创建线程的 ID。 const p…...
2024年河南省职业院校 技能大赛高职组 “大数据分析与应用” 赛项任务书(四)
2024 年河南省职业院校 技能大赛高职组 “大数据分析与应用” 赛项任务书(四)) 背景描述:任务一:Hadoop 完全分布式安装配置(25 分)任务二:离线数据处理(25 分࿰…...
Model Context Protocol - Prompts
1. 概述 Model Context Protocol (MCP) 提供了一种标准化的方式,使服务器能够向客户端暴露提示模板(prompts)。Prompts 是服务器提供的结构化消息和指令,用于与语言模型进行交互。客户端可以发现可用的提示、获取其内容ÿ…...
dify创建第一个Agent
1、首先LLM模型必须支持 Function Calling 由于deepseek-R1本地化部署时还不支持,所以使用 qwq模型。 2、创建空白 Agent 3、为Agent添加工具 4、测试 当未添加时间工具时 询问 时间 如下 5、开启时间工具 询问如下...
⭐算法OJ⭐判断二叉搜索树【树的遍历】(C++实现)Validate Binary Search Tree
图论入门【数据结构基础】:什么是树?如何表示树? 之前我们有分别讲解二叉树的三种遍历的相关代码实现: ⭐算法OJ⭐二叉树的前序遍历【树的遍历】(C实现)Binary Tree Preorder Traversal ⭐算法OJ⭐二叉树的…...
深度解析 | Android 13 Launcher3分页指示器改造:横线变圆点实战指南
一、需求背景与技术挑战 在Android 13系统定制开发中,我们面临将Launcher3桌面从传统双层架构优化为现代单层布局的挑战。原生系统采用的分页横线指示器在视觉呈现上存在两点不足: 风格陈旧不符合Material You设计规范 空间占用较大影响屏幕利用率 通…...
2. 商城前端部署
商城客户端前端部署 https://gitee.com/newbee-ltd/newbee-mall-api-go 使用开源新蜂商城的前端,git clone到本地 然后在vscode终端依次输入下列指令(配置好vue3相关环境的前提下): npm install npm i --legacy-peer-deps npm …...
鸿蒙生态开发
鸿蒙生态开发概述 鸿蒙生态是华为基于开源鸿蒙(OpenHarmony)构建的分布式操作系统生态,旨在通过开放共享的模式连接智能终端设备、操作系统和应用服务,覆盖消费电子、工业物联网、智能家居等多个领域。以下从定义与架构、核心技术…...
基于STM32进行FFT滤波并计算插值DA输出
文章目录 一、前言背景二、项目构思1. 确定FFT点数、采样率、采样点数2. 双缓存设计 三、代码实现1. STM32CubeMX配置和HAL库初始化2. 核心代码 四、效果展示和后话五、项目联想与扩展1. 倍频2. 降频3. 插值3.1 线性插值3.2 样条插值 一、前言背景 STM32 对 AD 采样信号进行快…...
【Oracle资源损坏类故障】:详细了解坏块
目录 1、物理坏块与逻辑坏块 1.1、物理坏块 1.2、逻辑坏块 2、两个坏块相关的参数 2.1、db_block_checksum 2.2、db_block_checking 3、检测坏块 3.1、告警日志 3.2、RMAN 3.3、ANALYZE 3.4、数据字典 3.5、DBVERIFY 4、修复坏块 4.1、RMAN修复 4.2、DBMS_REPA…...
996引擎-接口测试:背包
996引擎-接口测试:背包 背包测试NPC参考资料背包测试NPC CONSTANT = require("Envir/QuestDiary/constant/CONSTANT.lua"); MsgUtil = require("Envir/QuestDiary/utils/996/MsgUtil.lua");...
第三十一篇 数据仓库(DW)与商业智能(BI)架构设计与实践指南
目录 一、DW/BI架构核心理论与选型策略1.1 主流架构模式对比(1)Kimball维度建模架构(2)Inmon企业工厂架构(3)混合架构 二、架构设计方法论与实施步骤2.1 维度建模实战指南(1)模型选择…...
智能追踪台灯需求文档
一、项目背景 设计一款具备人体感知与动态追踪能力的智能台灯,实现以下核心目标: 自动开关:检测到人体活动时自动开启光源,无人时关闭以节省能耗。主动追踪:通过机械结构实时调整光照方向,确保用户始终处…...
给语言模型增加知识逻辑校验智能,识别网络信息增量的垃圾模式
给LLM增加逻辑校验模型,赋予其批判性智能。 网络系统上信息不断增长,相当部分是非纯粹的人类生成,而是由各种模型生成输出。模型持续从网络取得信息,生成信息输出到网络,AI生态系统与网络信息池之间陷入信息熵增循环。…...
Electron打包文件生成.exe文件打开即可使用
1 、Electron 打包,包括需要下载的内容和环境配置步骤 注意:Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架 首先需要电脑环境有Node.js 和 npm我之前的文章有关nvm下载node的说明也可以去官网下载 检查是否有node和npm环…...
单播、广播、组播和任播
文章目录 一、单播二、广播三、组播四、任播代码示例: 五、各种播的比较 一、单播 单播(Unicast)是一种网络通信方式,它指的是在网络中从一个源节点到一个单一目标节点对的传输模式。单播传输时,数据包从发送端直接发…...
AI生成移动端贪吃蛇游戏页面,手机浏览器打开即可玩
贪吃蛇游戏可计分,可穿墙,AI生成适配手机浏览器的游戏,代码如下: <!DOCTYPE html> <html lang"zh-CN"> <head> <meta charset"UTF-8"> <meta name"viewport" …...
Cursor+Claude-3.5生成Android app
一、Android Studio下载 https://developer.android.com/studio?hlzh-tw#get-android-studio 等待安装完成 二、新建工程 点击new project 选择Empty Activity 起一个工程名 当弹出这个框时 可以在settings里面选择No proxy 新建好后如下 点击右边模拟器,…...
NLP高频面试题(九)——大模型常见的几种解码方案
大模型常见的几种解码方案 在自然语言生成任务中,如何从模型生成的概率分布中选择合适的词汇,是影响文本质量的关键问题。常见的解码方法包括贪心搜索(Greedy Search)、束搜索(Beam Search)、随机采样&…...
QT Quick(C++)跨平台应用程序项目实战教程 3 — 项目基本设置(窗体尺寸、中文标题、窗体图标、可执行程序图标)
目录 1. 修改程序界面尺寸和标题 2. 窗体图标 3. 修改可执行程序图标 上一章创建好了一个初始Qt Quick项目。本章介绍基本的项目修改方法。 1. 修改程序界面尺寸和标题 修改Main.qml文件,将程序宽度设置为1200,程序高度设置为800。同时修改程序标题…...
Transformers x SwanLab:可视化NLP模型训练(2025最新版)
HuggingFace 的 Transformers 是目前最流行的深度学习训框架之一(100k Star),现在主流的大语言模型(LLaMa系列、Qwen系列、ChatGLM系列等)、自然语言处理模型(Bert系列)等,都在使用T…...
