当前位置: 首页 > news >正文

【Java】JVM虚拟机(基本概念、类加载机制)

一、基本概念

1、什么是JVM

        Java虚拟机(Java Virtual Machine,简称 JVM ),是java程序运行的核心组件之一,它为java程序运行提供了环境。其核心价值在于实现了" 一次编写,多处运行 " (Write once,run anywhere )的跨平台特性,还提供了内存管理、垃圾回收、安全性以及性能优化等。

2、JVM的组成

        JVM 的架构可分为类加载子系统、运行时数据区、执行引擎、本地方法接口四大核心模块,各模块协同工作完成字节码的加载、执行和资源管理。

二、类加载机制

1、概述

        Java 的类加载机制是 JVM 将 .class 字节码文件加载到内存中,并对数据进行校验、转换解析、初始化,最终形成可直接使用的 Java 类型的过程。

2、类的生命周期

3、类的加载过程

        类加载过程主要包括:加载、验证、准备、解析、初始化,五个阶段。

        a、加载

         该阶段主要是通过类的完全限定名获取类的二进制字节流,并生成一个代表该类的Class对象,并将其保存在元空间中。

  •  字节码来源
    • 本地文件系统(.class 文件);
    • 网络(如 Applet 从网络加载);
    • 动态生成(如 JavaCompiler 动态编译、CGLib 动态代理生成字节码);
    • 归档文件(如 JAR、WAR 包);
    • 数据库或其他数据源。

        b、验证

        该阶段主要验证class文件中的字节流包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

        c、准备

        该阶段是在元空间中为静态变量分配内存,并设置其默认初始值(非显示赋值)。

        d、解析

        该阶段只要是将常量池中的符号引用替换为直接引用

        e、初始化

        该阶段为类加载的最后一步,由<clinit>()编译器自动收集类中所有类变量的赋值和静态代码块中的语句,进行排序并执行。

4、类加载的时机

        在 Java 中,类的加载时机由 JVM 规范严格定义,主要分为主动引用被动引用两种情况。主动引用会触发类的初始化(初始化前的加载、验证、准备阶段会自动触发),而被动引用不会触发初始化。

a、主动引用

  • new() 创建类的实例

        当使用 new 关键字创建类的对象时,类会被初始化。

public class demo01 {public static void main(String[] args) {// 触发 MyClass 初始化MyClass obj = new MyClass();}
}
class MyClass {static {System.out.println("MyClass 初始化");}
}//结果:
MyClass 初始化
  • 调用类的静态方法

        当调用类的静态方法(static 方法)时,类会被初始化。

public class demo02 {public static void main(String[] args) {// 触发 Calculator 初始化int result = Calculator.add(1, 2);}
}
class Calculator {static {System.out.println("Calculator 初始化");}public static int add(int a, int b) {return a + b;}
}//结果:
Calculator 初始化
  • 访问静态变量

        当访问类的静态变量(static 变量)时,类会被初始化。

public class demo03 {public static void main(String[] args) {// 触发 Config 初始化int port = Config.PORT;System.out.println("======================");// 不触发 Config 初始化(直接从调用类的常量池获取值)int max = Config.MAX;System.out.println("main结束!!!");}
}class Config {static {System.out.println("Config 初始化");}public static int PORT = 8080; // 非 final 静态变量public static final int MAX= 100; // 编译期常量
}// 结果:
Config 初始化
======================
main结束!!!
  • 反射调用

        当使用反射newInstance()加载类时,类会被初始化。

public class demo04 {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {// 触发 MyClass 初始化Class cls = MyClass01.class;cls.newInstance();}
}
class MyClass01 {static {System.out.println("MyClass 初始化");}
}//结果:
MyClass 初始化
  • 初始化子类

        当初始化子类时,若父类尚未初始化,则会先触发父类的初始化。

public class demo05 {public static void main(String[] args) {// 触发 Parent 和 Child 依次初始化Child child = new Child();}
}
class Par {static {System.out.println("Parent 初始化");}
}
class Child extends Par {static {System.out.println("Child 初始化");}
}// 结果:
Parent 初始化
Child 初始化

b、被动引用

除主动引用外,所有引用类的方式都不会触发加载,称为被动引用

  • 创建数组

        创建类的数组时,不会触发类的初始化

public class demo06 {public static void main(String[] args) {data01[] data = new data01[10];System.out.println("main函数结束!");}
}
class data01{static {System.out.println("data01被初始化");}
}//结果:
main函数结束!
  • 通过子类引用父类的静态变量

        子类引用父类的静态变量时,仅触发父类的初始化,子类不会被初始化。

public class demo07 {public static void main(String[] args) {// 仅触发 Parent 初始化,Child 不会初始化System.out.println(Child.value); // 输出 10}
}
class Parent {static {System.out.println("Parent 初始化");}public static int value = 10;
}
class Child extends Parent {static {System.out.println("Child 初始化");}
}//结果:
Parent 初始化
10

5、类加载器

        类加载器是 Java 类加载机制的核心组件,负责将字节码文件加载到 JVM 内存中,并生成对应的 Class 对象。

1、类加载器类型

1. 启动类加载器

  • 加载范围:负责加载 JRE 核心类库(如 rt.jarresources.jar),路径通常为 $JAVA_HOME/jre/lib

2. 扩展类加载

  • 加载范围:负责加载 JRE 扩展目录中的类(如 jre/lib/ext 目录或 java.ext.dirs 系统属性指定的路径)

3. 应用程序类加载器

  • 加载范围:负责加载用户类路径上的类,即开发者编写的类和依赖的第三方库。

4. 自定义类加载器

  • 实现:用于实现特殊加载逻辑(如从网络、数据库加载类)。

2、双亲委派模型

        当类加载器收到一个类加载请求时,会首先委派给我自己的父类加载器,而不是自己加载,当向上委派到启动类加载器时,若其无法加载,则该类由子类自行尝试加载。

 

 

http://www.dtcms.com/a/298405.html

相关文章:

  • 苍穹外卖笔记集锦
  • 函数f(int a,int b),a和b的地址关系?
  • 《使用Qt Quick从零构建AI螺丝瑕疵检测系统》——5. 集成OpenCV:让程序拥有“视力”
  • 【NetTopologySuite库】使用Polygonizer线构面,并获取割边、悬挂边、无效环
  • ✨ 使用 Flask 实现头像文件上传与加载功能
  • TIM 实现定时中断【STM32L4】【实操】
  • 原生微信小程序如何调整开发版本
  • 全面解析MySQL(3)——CRUD进阶与数据库约束:构建健壮数据系统的基石
  • 数仓主题域划分
  • 机器学习(一)KNN,K近邻算法(K-Nearest Neighbors)
  • 不用电脑要不要关机?
  • win通过OpenSSL生成.ssh id_rsa密钥方法
  • 反射和SPI
  • 【DeepRare】疾病识别召回率100%
  • Haprxy七层代理
  • 呼叫中心系统管理权限功能配置
  • 深度学习篇---图片分辨率
  • Agentic RAG理解和简易实现
  • AMD官网下载失败,不让账户登录下载
  • 集合专题之Map
  • Kimi K2 大语言模型技术特性与应用实践分析
  • 初识opencv04——图像预处理3
  • 太极生两仪,两仪生四象,四象生八卦
  • mybatisX的自定义模板生成
  • 【深基12.例1】部分背包问题 Java
  • docker 挂载卷
  • 【C++】二叉搜索数
  • 使用Akshare获取股票历史数据
  • Avalonia 发布完cv到Linux上运行 出现字体丢失/不显示问题
  • [NLP]UPF基本语法及其在 native low power verification中的典型流程