【Java基础知识 47】一文读懂JVM类加载机制过程及原理

在这里插入图片描述

一、做一个小测试,通过注释,标注出下面两个类中每个方法的执行顺序,并写出studentId的最终值。

package com.nezha.javase;

public class Person1 {

    private int personId;

    public Person1() {
        setId(100);
    }

    public void setId(int id) {
        personId = id;
    }
}
package com.nezha.javase;

public class Student1 extends Person1 {

    private int studentId = 1;

    public Student1() {
    }

    @Override
    public void setId(int id) {
        super.setId(id);
        studentId = id;
    }

    public void getStudentId() {
        System.out.println("studentId = " + studentId);
    }
}
package com.nezha.javase;

public class Test1 {
    public static void main(String[] args) {
        Student1 student = new Student1();
        System.out.println("new Student() 完毕,开始调用getStudentId()方法");
        student.getStudentId();
    }
}

有兴趣的小伙伴试一下,相信我,用System.out.println标记一下每个函数执行的先后顺序,如果你全对了,下面的不用看了,大佬。

在这里插入图片描述

二、类的初始化步骤:

  1. 初始化父类中的静态成员变量和静态代码块 ;
  2. 初始化子类中的静态成员变量和静态代码块 ;
  3. 初始化父类的普通成员变量和代码块,再执行父类的构造方法;
  4. 初始化子类的普通成员变量和代码块,再执行子类的构造方法;

三、看看你写对了没?

package com.nezha.javase;

public class Person {

    private int personId;

    /**
     * 第一步,走父类无参构造函数
     */
    public Person() {
        // 1、第一步,走父类无参构造函数
        System.out.println("第一步,走父类无参构造函数");
        System.out.println("");
        setId(100);
    }

    /**
     * 第三步,通过super.setId(id);走父类发方法
     * @param id
     */
    public void setId(int id) {
        System.out.println("第三步,通过super.setId(id);走父类发方法~~~id="+id);
        personId = id;
        System.out.println("在父类:studentId 被赋值为 " + personId);
        System.out.println("");
    }
}
package com.nezha.javase;

public class Student extends Person {

    private int studentId = 1;

    /**
     * 在走子类无参构造函数前,会先执行子类的普通成员变量初始化
     * 第五步,走子类无参构造函数
     */
    public Student() {
        System.out.println("第五步,在走子类无参构造函数前,会先执行子类的普通成员变量初始化");
        System.out.println("第六步,走子类无参构造函数");
        System.out.println("");
    }

    /**
     * 第二步,走子类方法
     *
     * 走完super.setId(id);,第四步,再回此方法
     * @param id
     */
    @Override
    public void setId(int id) {
        System.out.println("第二步,走子类方法~~id="+id);
        // 3、第三步,走子类方法
        super.setId(id);
        studentId = id;
        System.out.println("第四步,再回此方法,在子类:studentId 被赋值为 " + studentId);
        System.out.println("");
    }

    /**
     * 第六步,走getStudentId()
     */
    public void getStudentId() {
        // 4、打印出来的值是100
        System.out.println("第七步,走getStudentId()");
        System.out.println("studentId = " + studentId);
        System.out.println("");
    }
}
package com.nezha.javase;

public class Test1 {
    public static void main(String[] args) {
        Student1 student = new Student1();
        System.out.println("new Student() 完毕,开始调用getStudentId()方法");
        // 打印出来的值是100
        System.out.println("#推测~~打印出来的值是100");
        student.getStudentId();
    }
}

在这里插入图片描述

下面通过图解JVM的方式,分析一下。

四、类的加载过程

在这里插入图片描述

1、加载

  • 通过一个类的全限定名获取定义此类的二进制字节流;
  • 将这个字节流代表的静态存储结构转化为方法区的运行时数据结构;
  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;

2、链接

(1)验证(Verify)

  • 目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全;
  • 主要包括四种验证:文件格式验证、元数据验证、字节码验证、符号引用验证;

(2)准备(Prepare)

  • 为类变量分配内存并且设置该类变量的默认初始值;
  • 这里不包含final修饰的static,因为final在编译的时候就会分配了,准备阶段会显示初始化;
  • 这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到堆中;

(3)解析

  • 将常量池内的符号引用转换为直接引用的过程
  • 例如静态代码块、静态变量的显示赋值
  • 事实上,解析操作往往会伴随着JVM在执行完初始化之后在执行
  • 符号引用就是一组符号来描述所引用的目标。符号引用的字面量形式明确定义在《Java虚拟机规范》的Class文件格式中。直接引用就是指- 向目标的指针、相对偏移量或一个间接定位到目标的句柄
  • 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等。对常量池中的CONSTANT_Filedref_info、CONSTANT_Class_info、CONSTANT_Methodref_info等。

3、初始化

  • 初始化阶段就是执行类构造器方法的过程;
  • 此方法不需要定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来;
  • 构造器方法中指令按语句在源文件中出现的顺序执行;
  • 类构造器方法不同于类的构造器。构造器是虚拟机视角下的类构造器;
  • 若该类具有父类,JVM会保证子类的类构造器执行前,父类的类构造器已经执行完毕;
  • 虚拟机必须保证一个类的类构造器方法在多线程下被同步加锁;

五、类加载器的分类

JVM类加载器包括两种,分别为引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)。

所有派生于抽象类ClassLoader的类加载器划分为自定义类加载器。

1、启动类加载器(引导类加载器)

  1. 启动类加载器是使用C/C++语言实现的,嵌套在JVM内部;
  2. Java的核心类库都是使用引导类加载器加载的,比如String;
  3. 没有父加载器;
  4. 是扩展类加载器和应用程序类加载器的父类加载器 ;
  5. 出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类 ;

在这里插入图片描述

2、扩展类加载器

  1. java语言编写
  2. 派生于ClassLoader类
  3. 父类加载器为启动类加载器
  4. 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的jar放在此目录下,也会自动由扩展类加载器加载

在这里插入图片描述

3、应用程序类加载器(系统类加载器)

  1. java语言编写
  2. 派生于ClassLoader类
  3. 父类加载器为扩展类加载器
  4. 它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库
  5. 该类加载器是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载的
  6. 通过ClassLoader.getSystemClassLoader()方法可以获得该类加载器

六、类加载器子系统的作用

在这里插入图片描述
类加载器子系统负责从文件系统或网络中加载class文件,class文件在文件开头有特定的文件标识。

ClassLoader只负责class文件的加载,至于它是否可以运行,则有执行引擎决定。

加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池的信息,可能还包括字符串字面量和数字常量(这部分常量信息是class文件中常量池部分的内存映射)。

七、总结

类的初始化步骤,这看似非常基础的话题,却实打实的难住了很多人,还总结了更为深入JVM的类的加载过程、类加载器的分类、类加载器的作用。

JVM面试题 这里写目录标题一、Java内存区域1、元空间会产生内存溢出吗?在什么情况下会产生内存溢出?2、解释Java堆空间及GC?3、说一下JVM的主要组成部分及其作用?4、说一下JVM运行时数据区?或者说下JVM内存模型?5、深拷贝和浅拷贝?6、说一下堆栈的区别?7、Java中堆和栈有什么区别?8、队列和栈是什么?有什么区别?9、虚拟机栈(线程私有)10、程序计数器(线程私有)11、什么是直接内存?二、HotSpot虚拟机对象探秘12、对象的创建过程13、为对象分配内存14、处理并发安全问题15、对象的访问定位16 阅读详情

相关推荐

【金三银四】Java基础知识面试题(2021最新版)

目录 前言 1、什么是B/S架构?什么是C/S架构 2、Java都有那些开发平台? 4、Java语言有哪些特点 6、什么是数据结构? 7、Java的数据结构有那些? 8、什么是OOP? 9、类与对象的关系? 10、Java中有几种数据类型 12、instanceof关键字的作用 13、什么是隐式转换,什么是显式转换 14、Char类型能不能转成int类型?能不能转化成string类型,能不能转成double类型 16、Java中的包装类都是那些? 17、一个java类中包含那些内

SQY0809的博客 1万+

当JSON遇上JVM:Fastjson反序列化漏洞的底层机制探秘

本文深入探讨了Fastjson反序列化漏洞的底层机制,揭示了攻击者如何通过精心构造的JSON数据操控JVM字节码执行流程,并分析了高版本中的autoType绕过技术。文章详细解析了漏洞原理、攻防对抗演进及防御方案,为开发者提供了安全实践建议。

weixin_28607671的博客 742

Java SE

Java SE 相关面试题

Kim-Hyunyeon的博客 708

JAVA高级面试题汇总及答案

JAVA高级面试题汇总及答案1.hashaMap原理源码2.synchronize关键字1.6之后的优化,(偏向轻量级锁,重量级锁)3.双亲委派是什么4.类加载过程中可以动态改字节码吗?5.如何定位线上问题,CPU100%6.redis线程模型,分布式锁,除了redis还有哪些可以用来分布式锁7.了解springboot吗?springboot自动装配是如何实现的?8.RPC框架用过哪些?谈一下内...

wcy199113的博客 1716

Minecraft Forge服务器本地部署:Java环境、JVM调优与Mod加载原理详解

Minecraft Forge服务器本质上是一个深度定制的Java应用,其稳定运行依赖于精准匹配的Java版本、合理的JVM内存与GC策略,以及符合服务端规范的Mod加载机制。理解JVM启动流程(类加载、堆内存分配、GC行为)是解决‘白屏’‘卡在Loading World’等常见问题的基础;掌握ModLoader(如ModLauncher)如何扫描mods目录、解析依赖顺序、隔离客户端代码,则能规避90%的mod冲突与NoClassDefFoundError。技术价值在于将黑盒部署转化为可监控、可调试、可自

weixin_31102231的博客 397

2020年 Java面试题整理 最新Java面试题2020

文章目录1、类加载和实例化2、Java是值传递还是引用传递3、类加载的主要过程4、什么是GC5、简述垃圾回收过程6、内存泄漏7、导致内存泄漏的场景8、Java中堆和栈的区别9、ArrayList、LinkedList、Vector的区别10、StringBuffer和StringBuilder的区别11、HashMap、HashTable、TreeMap区别12、synchronized 与 Lo...

情怀中的释然~ 3万+

Java异常处理实战:从JVM机制到Spring全局拦截

Java异常处理是保障系统稳定性的核心能力,其本质源于JVM的字节码校验机制与编译期强制检查原理。Checked Exception体现对外部不可控状态的责任契约,而RuntimeException则指向代码逻辑缺陷。在Spring Boot生态中,异常需经HandlerExceptionResolver多层拦截,涉及@ExceptionHandler优先级、ResponseStatusExceptionResolver执行时机及Filter/Interceptor异常逃逸等关键问题。结合try-with-

weixin_30911451的博客 408

Java 岗史上最全八股文面试真题汇总,堪称 2023 年面试天花板

为了不影响大家的阅读体验,这篇 Java 八股文的面试真题已经为大家整理好了,希望这份八股文笔记可以帮助今年要面试的小伙伴拿到自己心仪的 offer,当然以上的面试真题仅供参考,也可以在评论区讨论~

dongjia9的博客 8231

Forge服务器启动原理与JVM配置实战指南

Forge服务器本质是一个基于Java SPI机制的模块化加载平台,其启动过程依赖JVM类加载顺序、SPI服务发现及字节码增强(如Mixin)等底层机制。理解这一原理,是解决‘双击jar无响应’‘连接被拒绝’‘Mod静默失效’等高频问题的关键。技术价值在于规避因类路径错误、内存不足或绑定地址误配导致的服务端启动失败;典型应用场景涵盖本地开发、云服务器部署及NAS家庭服务器搭建。本文深入剖析Forge服务端的物理文件结构、JVM参数调优(特别是-Xms3G安全基线)、server-ip语义差异及mixinex

weixin_34293911的博客 448

Minecraft Forge模组开发:Java沙盒环境与事件总线原理

Minecraft Forge模组开发本质上是面向Java运行时约束的嵌入式应用工程,其核心在于构建受控的双JVM沙盒环境与参与游戏生命周期的事件治理。理解类加载器隔离、MCP映射表语义对齐及Gradle插件驱动的构建流程,是规避NoClassDefFoundError等典型错误的前提;而事件监听并非简单回调注册,实为基于Forge事件总线(Event Bus)的分阶段、可取消、多总线协同机制。该技术体系广泛应用于Modding生态扩展、客户端功能增强与服务端行为定制等场景,是Java开发者切入游戏引擎二次

weixin_33391446的博客 333

JVM类加载过程详解

除了上面三个自带的以外,用户还能制定自己的类加载器,但是所有自定义的类加载器都应该继承自java.lang.ClassLoader。比如热部署、tomcat都会用到自定义类加载器。在java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,来定制类的加载方式。为什仫要自定义类加载器?1. 隔离加载类2. 修改类加载的方式3. 扩展加载源4. 防止源码泄露用户自定义类加载器实现步骤:

悦分享 1226

Java 的类加载机制

01、字节码 在聊 Java 类加载机制之前,需要先了解一下 Java 字节码,因为它和类加载机制息息相关。 计算机只认识 0 和 1,所以任何语言编写的程序都需要编译成机器码才能被计算机理解,然后执行,Java 也不例外。 Java 在诞生的时候喊出了一个非常牛逼的口号:“Write Once, Run Anywhere”,为了达成这个目的,Sun 公司发布了许多可以在不同平台(Windows、Linux)上运行的 Java 虚拟机(JVM)——负责载入和执行 Java 编译后的字节码。 .

YABUSHAN 541

Java:Java虚拟机(JVM)原理_2024-07-14_19-47-56.Tex

垃圾回收机制是Java虚拟机中一个关键的内存管理技术,它通过不同的算法和收集器,自动识别并回收不再使用的对象,从而避免了内存泄漏和溢出的问题。理解垃圾回收的基本概念和算法,可以帮助开发者更有效地管理Java应用程序的性能和资源。

419

Java面试题超详细讲解系列之四【Jvm篇】

Java面试题超详细讲解系列【jvm篇】,专栏持续更新

白大锅的博客,毕设WangLoveBai_999 7212

Java面试题-JVM

指的是垃圾收集过程中,虚拟机暂停所有应用线程的执行,以确保在清理内存时不会有新的数据改动,保证垃圾收集的安全性和一致性。STW是垃圾收集过程的一部分,影响程序的暂停时间。OopMap: Object-Oriented Programming Map的缩写,用于垃圾收集时快速定位对象内部的引用。在运行时,OopMap可以提供每个方法执行点上的活动引用的准确位置,帮助垃圾收集器识别哪些是指向对象的引用,从而准确地进行标记和清理。安全点(Safepoint)

Roc的博客 722

在LinuxMint 22.1(Ubuntu24.04)上安装使用同花顺远航版

Linux用户成功在LinuxMint22.1系统上通过Wine9.0运行同花顺远航版,解决了长期困扰的股票行情软件问题。此前Linux原生版同花顺功能简陋且停止更新,Wine版通达信存在显示问题。作者作为自由软件支持者,通过调整Wine配置文件解决了高分屏显示异常问题,实现了远航版的正常使用。期待同花顺能重启Linux原生版开发,支持更多处理器架构,完善国产软件生态。该方案为Linux股票软件用户提供了实用参考。

5141

ADS笔记,新旧两组仿真数据进行绘图和列表对比

原理图器件参数的不同,怎么进行对比观看,操作如下。

彭辉荣的博客 3870

GEM5教程--gem5开始之旅(一)

GEM5系列教程--gem5开始之旅一、建立GEM5 GEM5模拟器是一个用于计算机系统结构研究的模块化平台,包含系统级别的结构以及处理器的微体系结构。读者若想详细的了解,请查看其官方文档GEM5文档 读者如果想要入门GEM5的话,可以参考Learning_GEM5这个网站,这里面有较为详细的教程,可以带读者从入门到精通。小编我对GEM5的入门学习也是从这个Learning_GEM5这个网站学习的...

qq_43381135的博客 3万+

项目管理面试常见问题及答案

1. 项目管理软件工具知识,   2. 编制项目计划的技术,   3. 人员管理技能   4. 沟通技能   5. 原理体系知识(标生命周期和项目管理)。 项目管理软件工具知识   问题1:工期和工作量之间的差异是什么?   答案1:工期是商业/日历上的天数,与人数和工作量无关。工作量是与日历天数无关的人的工作。例如:   一天的工作量对于一个一只花50%在时间在上面的人来说,他的工期就是两天。...

okbin1991的博客 2845

(一)DaVinci Developer AutoSAR工具 如何新建SWC、Component、RTE工程,超级详细步骤,赚到

​ 1,创建SWC,第一步需要创建一个App组件类型,首先点击Object Brower菜单,然后左键Application Component Types 选项,然后右键New Application Component Type,组件类型的作用是来后续实例一个Compoent 2、 Properties 选项卡中Nane中输入Type的名字,注意根据规范命名规则已CtAp开头,其他默认就好 ​

weixin_42602687的博客 3579

Allegro如何改变线宽操作指导

用Allegro做pcb设计的时候,改变走线线宽是非常常用的功能,如下图。线宽目前是12mil,需要把线宽改成15mil。如何改变线宽操作指导。

weixin_54787054的博客 4254

ADT MCP Server 把 ABAP 开发带进 Agent 模式

今天讨论 ADT MCP Server,不能只把它看成 Visual Studio Code 里多出来的一个开关。它真正有意思的地方,在于它把 ABAP 后端开发里那些原本需要手工点击、手工创建、手工激活、手工查服务元数据的动作,包装成一组可以被 GitHub Copilot 这类 coding agent 调用的工具。SAP 在 RAP130 练习里把它描述为运行在 ADT for Visual Studio Code 扩展内部的本地 HTTP Server,它实现的是 Model Context Pro

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 185

还在用 RaiDrive/Rclone 挂载网盘?教您使用Windows 原生 WebDAV 丝滑直连 AList/Openlist,让你的网盘秒变本地硬盘!

网盘文件分散管理?😩 别再依赖第三方工具了!本文教你如何在 Windows 下,利用原生 WebDAV 功能,将 Openlist 网盘直接映射为本地硬盘!💻 操作简单,告别繁琐,让你的云端文件像本地文件一样丝滑!🚀 轻松实现高效管理,快来体验吧!

XiaoqiangClub的博客 2978

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

上一篇: MongoDB 4.0支持事务了,还有多少人想用MySQL呢?
下一篇: 技术瓶颈?如何解决MongoDB超大块数据问题?
哪 吒
哪 吒 2022年度博客之星TOP 1 2022年度博客之星TOP 1 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 59万+粉丝 2953原创
评论 59
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值