完整的类在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;}
}


代码作用和功能说明

  1. 类结构和继承

    • BaseCalculator 是一个抽象父类,提供基础值和方法,模拟计算器的基本功能。
    • Calculator 继承 BaseCalculator,并实现 Operable 接口,提供加法等操作。
    • AdvancedCalculator 是 Calculator 的子类,增加了平方计算功能。
  2. 静态成员

    • MAX_CALCULATIONS 是静态常量,限制计算次数(示例中未强制执行,仅展示概念)。
    • calculationCount 是静态变量,记录创建的计算器实例数。
    • getCalculationCount() 是静态方法,提供全局访问。
  3. 本地方法

    • specialCalculation() 使用 native 关键字,假设由本地代码实现特殊计算(实际需要 JNI 实现)。
  4. 线程安全

    • multiply() 使用 synchronized 确保多线程环境下安全更新 currentResult
    • volatile 修饰 currentResult,保证线程间可见性。
  5. 嵌套类和枚举

    • CalculationLogger 是静态嵌套类,用于记录计算日志。
    • OperationType 是枚举,定义支持的操作类型。
  6. 功能实现

    • 支持加法(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 会通过类加载器加载该类及其相关类(BaseCalculatorOperableAdvancedCalculator 等)。这涉及到方法区和运行时常量池的初始化。

底层原理
  1. 类加载

    • JVM 使用类加载器(如 AppClassLoader)加载 Calculator.class 文件。
    • 类文件被解析后,JVM 在方法区(Java 8 中为 Metaspace)分配内存,存储类的元数据,包括:
      • 类名(com.example.Calculator
      • 父类(BaseCalculator
      • 接口(Operable
      • 字段信息(MAX_CALCULATIONScalculationCount 等)
      • 方法表(addmultiplyspecialCalculation 等)
      • 字节码(每个方法的指令序列)。
  2. 运行时常量池

    • 方法区中的一部分逻辑区域为运行时常量池(Runtime Constant Pool),存储类文件中 constant_pool 表的运行时表示。
    • 例如,MAX_CALCULATIONS = 100 的值 100、字符串 "已加载Calculator类..."、方法引用(如 System.out.println)等都被放入常量池。
    • 在 HotSpot JVM 中,运行时常量池的实现依赖于 Metaspace 中的 ConstantPool 对象。
  3. 静态初始化

    • 类加载完成后,JVM 执行 <clinit> 方法(类初始化方法),运行静态初始化块:
      static {System.out.println("已加载Calculator类。最大允许的计算次数: " + MAX_CALCULATIONS);
      }
      
    • 这会在方法区中为 calculationCount 分配内存并初始化为 0,并在 Java 堆中分配字符串对象(常量池引用)。
源代码层面
  • HotSpot JVM 的 InstanceKlass 类表示方法区中的类元数据。
  • ConstantPool 对象管理运行时常量池,存储符号引用(如字段和方法的 CONSTANT_Fieldref_info)。

2. 对象创建(Java 堆和 Java 虚拟机栈)

流程概述

        当执行 Calculator calc = new Calculator(5);  时,JVM 创建 Calculator 对象实例,并分配栈帧来执行构造方法。

底层原理
  1. Java 堆分配

    • JVM 在堆的年轻代(Young Generation)中的 Eden 区为 Calculator 对象分配内存。
    • 对象包含实例字段:
      • baseValue(继承自 BaseCalculator
      • currentResult
      • tempLog
    • 对象头(Object Header)包含元数据,如指向方法区中 Calculator 类元信息的指针(klass 指针)。
  2. Java 虚拟机栈

    • 为调用 Calculator(int) 构造方法,JVM 在当前线程的栈中推送一个新的栈帧(Frame)。
    • 栈帧结构:
      • 局部变量表:存储 this(对象引用)和参数 initialValue
      • 操作数栈:用于计算(如 this.currentResult = initialValue)。
      • 常量池引用:指向运行时常量池中构造方法的相关条目。
    • 执行流程:
      • super(); 调用 BaseCalculator 的构造方法,分配一个父类栈帧。
      • this.currentResult = initialValue; 将 5 存入堆中的对象字段。
      • 实例初始化块 {} 执行,更新 calculationCount
  3. PC 寄存器

    • PC(Program Counter)寄存器记录当前线程正在执行的字节码指令地址。
    • 例如,在构造方法中,PC 指向 invokespecial(调用 super())或 putfield(设置 currentResult)指令。
源代码层面
  • HotSpot 的 oopDesc 表示堆中的对象,markOop 是对象头。
  • frame 类管理栈帧,interpreter 模块执行字节码。

3. 方法调用(Java 虚拟机栈和本地方法栈)

流程概述

        执行 calc.add(10, 15); 和 calc.specialCalculation(20); 时,JVM 分别调用普通方法和本地方法。

底层原理
  1. 普通方法调用(Java 虚拟机栈)

    • 为 add(int, int) 创建栈帧:
      • 局部变量表:thisa(10)、b(15)。
      • 操作数栈:计算 a + b,结果存入 currentResult
    • PC 寄存器更新为 add 方法的字节码地址。
    • 方法返回后,栈帧弹出。
  2. 本地方法调用(本地方法栈)

    • 调用 specialCalculation(int) 时,JVM 使用 Java Native Interface(JNI)。
    • 在本地方法栈(Native Method Stack)分配栈帧,存储 JNI 调用参数。
    • PC 寄存器值未定义(本地方法不由 JVM 解释执行)。
    • JNI 调用本地库(如 .dll 或 .so 文件),假设返回结果。
  3. 同步方法(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)回收其内存。

底层原理
  1. 可达性分析

    • GC 从根集(GC Roots)开始标记:
      • 栈中的局部变量(如 calc)。
      • 方法区中的静态变量(如 calculationCount)。
    • 若 calc 无引用,则标记为不可达。
  2. 年轻代回收(Minor GC)

    • calc 在 Eden 区创建,若仍存活,可能晋升到 Survivor 区。
    • Minor GC 使用复制算法(Copying Algorithm):
      • 将 Survivor 中的存活对象移动到另一个 Survivor 或老年代。
      • 清空 Eden 和当前 Survivor。
  3. 老年代回收(Major GC)

    • 若 calc 存活多次 Minor GC,晋升到老年代(Tenured Generation)。
    • 使用标记-清除(Mark-Sweep)或标记-整理(Mark-Compact)算法:
      • 标记存活对象。
      • 清除不可达对象(如 calc),回收内存。
  4. Metaspace(方法区)回收

    • 若 Calculator 类不再被使用(无实例且类加载器可回收),Metaspace 中的元数据和常量池条目被回收。
    • Java 8 中 Metaspace 使用本地内存,受 -XX:MaxMetaspaceSize 控制。
源代码层面
  • GenCollectedHeap 管理堆的分代。
  • G1CollectedHeap(默认 GC)实现分代回收。
  • MetaspaceUtils 处理 Metaspace 回收。

6. 完整流程总结

  1. 方法区和常量池:类加载,元数据和常量存储。
  2. Java 堆:对象在 Eden 区创建,字段存储实例数据。
  3. Java 虚拟机栈:栈帧执行构造方法和普通方法。
  4. PC 寄存器:跟踪指令地址。
  5. 本地方法栈:执行 native 方法。
  6. GC 销毁:对象不可达后,Minor/Major GC 回收堆内存,Metaspace 回收类元数据。

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

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

相关文章

向量叉积的应用——正反画画

1 解题思路 解题思路涉及的向量积相关知识 c实现 #include<iostream> #include<vector>using namespace std;struct TrianglePoint {int x;int y; };int momentForce(TrianglePoint A, TrianglePoint B, TrianglePoint C) {//AB向量&#xff1a;(B.x-A.x, B.y-A.…

构建自定义MCP天气服务器:集成Claude for Desktop与实时天气数据

构建自定义MCP天气服务器:集成Claude for Desktop与实时天气数据 概述 本文将指导开发者构建一个MCP(Model Control Protocol)天气服务器,通过暴露get-alerts和get-forecast工具,为Claude for Desktop等客户端提供实时天气数据支持。该方案解决了传统LLM无法直接获取天气…

Web安全策略CSP详解与实践

引言 &#xff1a;在黑客攻击频发的今天&#xff0c;你的网站是否像“裸奔”一样毫无防护&#xff1f;跨站脚本&#xff08;XSS&#xff09;、数据注入等攻击随时可能让用户数据泄露。今天我们将揭秘一个网站的隐形保镖——内容安全策略&#xff08;CSP&#xff09;&#xff0c…

HC-05与HC-06蓝牙配对零基础教程 以及openmv识别及远程传输项目的概述

这个是上一年的项目&#xff0c;之前弄得不怎么完整&#xff0c;只有一个openmv的&#xff0c;所以openmv自己去我主页找&#xff0c;这篇主要讲蓝牙 这个是我在使用openmv连接单片机1然后单片机1与单片机2通过蓝牙进行通信 最终实现的效果是&#xff1a;openmv识别到图形和数…

点云分割方法

点云分割 通过判断三维距离&#xff0c;实现对创建3团点云的分割 通过判断三维距离&#xff0c;实现对创建3团点云的分割 * 点云1 gen_object_model_3d_from_points (rand(100), rand(100),rand(100), Points1)* 点云2 gen_object_model_3d_from_points (rand(100), 2rand(100…

SpringBoot3使用CompletableFuture时java.util.ConcurrentModificationException异常解决方案

问题描述 在Spring Boot 3项目中&#xff0c;使用CompletableFuture进行异步编程时&#xff0c;偶发{"code":500,"msg":"java.util.ConcurrentModificationException"}异常&#xff0c;但代码中并未直接操作List或CopyOnWriteArrayList等集合类…

细说卫星导航:测距定位原理

测距定位原理 1. 伪距测量技术 核心原理&#xff1a;卫星发射信号&#xff0c;用户接收并记录传播时间&#xff0c;乘以光速得到距离&#xff08;伪距&#xff09;。 技术细节&#xff1a; 信号传播路径分析 信号结构&#xff1a; 卫星信号包含三部分&#xff1a; 载波&…

Linux系统管理与编程09:任务驱动综合应用

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 [环境] windows11、centos9.9.2207、zabbix6、MobaXterm、Internet环境 [要求] zabbix6.0安装环境&#xff1a;Lamp&#xff08;linux httpd mysql8.0 php&#xff09; [步骤] 5 …

RAG(Retrieval-Augmented Generation)基建之PDF解析的“魔法”与“陷阱”

嘿&#xff0c;亲爱的算法工程师们&#xff01;今天咱们聊一聊PDF解析的那些事儿&#xff0c;简直就像是在玩一场“信息捉迷藏”游戏&#xff01;PDF文档就像是个调皮的小精灵&#xff0c;表面上看起来规规矩矩&#xff0c;但当你想要从它那里提取信息时&#xff0c;它就开始跟…

RK3568 I2C底层驱动详解

前提须知&#xff1a;I2C协议不懂的话就去看之前的内容吧&#xff0c;这个文章需要读者一定的基础。 RK3568 I2C 简介 RK3568 支持 6 个独立 I2C: I2C0、I2C1、I2C2、I2C3、I2C4、I2C5。I2C 控制器支持以下特性: ① 兼容 i2c 总线 ② AMBA APB 从接口 ③ 支持 I2C 总线主模式…

UNIX网络编程笔记:基本TCP套接字编程

一、socket函数 一、socket函数核心参数与协议组合 函数原型与基本功能 #include <sys/socket.h> int socket(int family, int type, int protocol);• 功能&#xff1a;创建通信端点&#xff08;套接字&#xff09;&#xff0c;返回描述符供后续操作。 • 返回值&#…

JSON在AutoCAD二次开发中应用场景及具体案例

配置文件的读取 在AutoCAD插件开发中&#xff0c;可能需要生成、修改、读取配置文件中一些参数或设置。JSON格式的配置文件易于编写和修改&#xff0c;且可以方便地反序列化为对象进行使用。 运行后效果如下 using Autodesk.AutoCAD.ApplicationServices; using Autodesk.Au…

自由学习记录(46)

CG语法的数据类型 // uint : 无符号整数&#xff08;32位&#xff09; // int : 有符号整数&#xff08;32位&#xff09; // float : 单精度浮点数&#xff08;32位&#xff09;&#xff0c;通常带后缀 f&#xff08;如 1.0f&#xff09; // half : 半精度浮…

解决Selenium滑动页面到指定元素,点击失效的问题

White graces&#xff1a;个人主页 &#x1f649;专栏推荐:Java入门知识&#x1f649; &#x1f439;今日诗词:君失臣兮龙为鱼&#xff0c;权归臣兮鼠变虎&#x1f439; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主&#x1f64f; ⛳️点赞 ☀️收藏⭐️关注&#x1f4…

Vue基础

目录 -Vue基础- 1、插值表达式 {{}} 2、Vue核心特性&#xff1a;响应式 3、开发者工具Vue Devtools(极简插件下载) 4、Vue指令 v-text v-html v-bind v-on v-if v-show v-for v-model 5、Vue指令修饰符 .stop .prevent .capture .self .once .enter、.tab、…

收数据花式画图plt实战

目录 Python plt想把纵坐标化成对数形式代码 子图ax. 我又有ax scatter&#xff0c;又有ax plot&#xff0c;都要去对数 数字接近0&#xff0c;取对数没有定义&#xff0c;怎么办 创建数据 添加一个小的常数以避免对数未定义的问题 创建一个figure和一个子图ax 在子图a…

二项式分布(Binomial Distribution)

二项式分布&#xff08;Binomial Distribution&#xff09; 定义 让我们来看看玩板球这个例子。假设你今天赢了一场比赛&#xff0c;这表示一个成功的事件。你再比了一场&#xff0c;但你输了。如果你今天赢了一场比赛&#xff0c;但这并不表示你明天肯定会赢。我们来分配一个…

【算法工程】大模型开发之windows环境的各种安装

1. 背景 最近由于研究需要&#xff0c;我购置了两块3090显卡&#xff0c;以便在家中进行一些小规模的实验。为此&#xff0c;还更换了主机。当然&#xff0c;新系统上少不了要安装各种开发环境。从开发体验来看&#xff0c;macOS无疑更为流畅&#xff0c;但为了确保所有环境都能…

论文阅读笔记:Denoising Diffusion Probabilistic Models (2)

接论文阅读笔记&#xff1a;Denoising Diffusion Probabilistic Models (1) 3、论文推理过程 扩散模型的流程如下图所示&#xff0c;可以看出 q ( x 0 , 1 , 2 ⋯ , T − 1 , T ) q(x^{0,1,2\cdots ,T-1, T}) q(x0,1,2⋯,T−1,T)为正向加噪音过程&#xff0c; p ( x 0 , 1 , …

vscode查看文件历史git commit记录

方案一&#xff1a;GitLens 在vscode扩展商店下载GitLens 选中要查看的文件&#xff0c;vscode界面右上角点击GitLens的图标&#xff0c;选择Toggle File Blame 界面显示当前打开文件的所有修改历史记录 鼠标放到某条记录上&#xff0c;可以看到记录详情&#xff0c;选中O…