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

一、基本概念

1、什么是JVM

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

2、JVM的组成

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

【Java】JVM虚拟机(基本概念、类加载机制)_第1张图片

二、类加载机制

1、概述

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

2、类的生命周期

【Java】JVM虚拟机(基本概念、类加载机制)_第2张图片

3、类的加载过程

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

        a、加载

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

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

        b、验证

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

        c、准备

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

        d、解析

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

        e、初始化

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

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、双亲委派模型

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

【Java】JVM虚拟机(基本概念、类加载机制)_第3张图片

 

 

你可能感兴趣的:(java,jvm,开发语言,经验分享,双亲委派模型,类加载)