看完这个咱就是说不再反感 Java 的类加载机制了

Java面试核心知识点与高频考点深度解析 Java作为企业级开发的主流语言,其技术体系涵盖语言基础、并发编程、JVM原理等核心维度。理解面向对象特性、集合框架等基础概念是开发者的必备技能,而深入掌握HashMap树化优化、ConcurrentHashMap分段计数等底层原理则能体现技术深度。在并发编程领域,线程池参数配置、锁机制实现原理等知识点尤为重要,合理使用ConcurrentHashMap等并发容器能有效提升系统性能。JVM内存模型与GC调优直接影响应用稳定性,了解ZGC等新一代收集器特性有助于应对高并发场景。系统设计方面,Spring框架的 阅读详情

很长一段时间里,我对 Java 的类加载机制都非常的抗拒,因为我觉得太难理解了。但为了成为一名优秀的 Java 工程师,我决定硬着头皮研究一下。

01、字节码

在聊 Java 类加载机制之前,需要先了解一下 Java 字节码,因为它和类加载机制息息相关。

计算机只认识 0 和 1,所以任何语言编写的程序都需要编译成机器码才能被计算机理解,然后执行,Java 也不例外。

Java 在诞生的时候喊出了一个非常牛逼的口号:“Write Once, Run Anywhere”,为了达成这个目的,Sun 公司发布了许多可以在不同平台(Windows、Linux)上运行的 Java 虚拟机(JVM)——负责载入和执行 Java 编译后的字节码。

到底 Java 字节码是什么样子,我们借助一段简单的代码来看一看。

源码如下:

package com.cmower.java_demo;

public class Test {

    public static void main(String[] args) {
        System.out.println("沉默王二");
    }

}

代码编译通过后,通过 xxd Test.class 命令查看一下这个字节码文件。

xxd Test.class
00000000: cafe babe 0000 0034 0022 0700 0201 0019  .......4."......
00000010: 636f 6d2f 636d 6f77 6572 2f6a 6176 615f  com/cmower/java_
00000020: 6465 6d6f 2f54 6573 7407 0004 0100 106a  demo/Test......j
00000030: 6176 612f 6c61 6e67 2f4f 626a 6563 7401  ava/lang/Object.
00000040: 0006 3c69 6e69 743e 0100 0328 2956 0100  ..<init>...()V..
00000050: 0443 6f64 650a 0003 0009 0c00 0500 0601  .Code...........
00000060: 000f 4c69 6e65 4e75 6d62 6572 5461 626c  ..LineNumberTabl

感觉有点懵逼,对不对?

懵就对了。

这段字节码中的 cafe babe 被称为“魔数”,是 JVM 识别 .class 文件的标志。文件格式的定制者可以自由选择魔数值(只要没用过),比如说 .png 文件的魔数是 8950 4e47。

至于其他内容嘛,可以选择忘记了。

02、类加载过程

了解了 Java 字节码后,我们来聊聊 Java 的类加载过程。

Java 的类加载过程可以分为 5 个阶段:载入、验证、准备、解析和初始化。这 5 个阶段一般是顺序发生的,但在动态绑定的情况下,解析阶段发生在初始化阶段之后。

1)Loading(载入)

JVM 在该阶段的主要目的是将字节码从不同的数据源(可能是 class 文件、也可能是 jar 包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的 java.lang.Class 对象。

2)Verification(验证)

JVM 会在该阶段对二进制字节流进行校验,只有符合 JVM 字节码规范的才能被 JVM 正确执行。该阶段是保证 JVM 安全的重要屏障,下面是一些主要的检查。

  • 确保二进制字节流格式符合预期(比如说是否以 cafe bene 开头)。
  • 是否所有方法都遵守访问控制关键字的限定。
  • 方法调用的参数个数和类型是否正确。
  • 确保变量在使用之前被正确初始化了。
  • 检查变量是否被赋予恰当类型的值。

3)Preparation(准备)

JVM 会在该阶段对类变量(也称为静态变量,static 关键字修饰的)分配内存并初始化(对应数据类型的默认初始值,如 0、0L、null、false 等)。

也就是说,假如有这样一段代码:

public String chenmo = "沉默";
public static String wanger = "王二";
public static final String cmower = "沉默王二";

chenmo 不会被分配内存,而 wanger 会;但 wanger 的初始值不是“王二”而是 null。

需要注意的是,static final 修饰的变量被称作为常量,和类变量不同。常量一旦赋值就不会改变了,所以 cmower 在准备阶段的值为“沉默王二”而不是 null。

4)Resolution(解析)

该阶段将常量池中的符号引用转化为直接引用。

what?符号引用,直接引用?

符号引用以一组符号(任何形式的字面量,只要在使用时能够无歧义的定位到目标即可)来描述所引用的目标。

在编译时,Java 类并不知道所引用的类的实际地址,因此只能使用符号引用来代替。比如 com.Wanger 类引用了 com.Chenmo 类,编译时 Wanger 类并不知道 Chenmo 类的实际内存地址,因此只能使用符号 com.Chenmo。

直接引用通过对符号引用进行解析,找到引用的实际内存地址。

5)Initialization(初始化)

该阶段是类加载过程的最后一步。在准备阶段,类变量已经被赋过默认初始值,而在初始化阶段,类变量将被赋值为代码期望赋的值。换句话说,初始化阶段是执行类构造器方法的过程。

oh,no,上面这段话说得很抽象,不好理解,对不对,我来举个例子。

String cmower = new String("沉默王二");

上面这段代码使用了 new 关键字来实例化一个字符串对象,那么这时候,就会调用 String 类的构造方法对 cmower 进行实例化。

03、类加载器

聊完类加载过程,就不得不聊聊类加载器。

一般来说,Java 程序员并不需要直接同类加载器进行交互。JVM 默认的行为就已经足够满足大多数情况的需求了。不过,如果遇到了需要和类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就不得不花大量的时间去调试 
ClassNotFoundException 和 NoClassDefFoundError 等异常。

对于任意一个类,都需要由它的类加载器和这个类本身一同确定其在 JVM 中的唯一性。也就是说,如果两个类的加载器不同,即使两个类来源于同一个字节码文件,那这两个类就必定不相等(比如两个类的 Class 对象不 equals)。

站在程序员的角度来看,Java 类加载器可以分为三种。

1)启动类加载器(Bootstrap Class-Loader),加载 jre/lib 包下面的 jar 文件,比如说常见的 rt.jar。

2)扩展类加载器(Extension or Ext Class-Loader),加载 jre/lib/ext 包下面的 jar 文件。

3)应用类加载器(Application or App Clas-Loader),根据程序的类路径(classpath)来加载 Java 类。

来来来,通过一段简单的代码了解下。

public class Test {

    public static void main(String[] args) {
        ClassLoader loader = Test.class.getClassLoader();
        while (loader != null) {
            System.out.println(loader.toString());
            loader = loader.getParent();
        }
    }

}

每个 Java 类都维护着一个指向定义它的类加载器的引用,通过 类名.class.getClassLoader()可以获取到此引用;然后通过 loader.getParent() 可以获取类加载器的上层类加载器。

这段代码的输出结果如下:

sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742

第一行输出为 Test 的类加载器,即应用类加载器,它是 sun.misc.Launcher$AppClassLoader类的实例;第二行输出为扩展类加载器,是 sun.misc.Launcher$ExtClassLoader 类的实例。那启动类加载器呢?

按理说,扩展类加载器的上层类加载器是启动类加载器,但在我这个版本的 JDK 中, 扩展类加载器的 getParent() 返回 null。所以没有输出。

04、双亲委派模型

如果以上三种类加载器不能满足要求的话,程序员还可以自定义类加载器(继承 java.lang.ClassLoader 类),它们之间的层级关系如下图所示。

这种层次关系被称作为双亲委派模型:如果一个类加载器收到了加载类的请求,它会先把请求委托给上层加载器去完成,上层加载器又会委托上上层加载器,一直到最顶层的类加载器;如果上层加载器无法完成类的加载工作时,当前类加载器才会尝试自己去加载这个类。

PS:双亲委派模型突然让我联想到朱元璋同志,这个同志当上了皇帝之后连宰相都不要了,所有的事情都亲力亲为,只有自己没精力没时间做的事才交给大臣们去干。

使用双亲委派模型有一个很明显的好处,那就是 Java 类随着它的类加载器一起具备了一种带有优先级的层次关系,这对于保证 Java 程序的稳定运作很重要。

上文中曾提到,如果两个类的加载器不同,即使两个类来源于同一个字节码文件,那这两个类就必定不相等——双亲委派模型能够保证同一个类最终会被特定的类加载器加载。

05、最后

硬着头皮翻看了大量的资料,并且动手去研究以后,我发现自己竟然对 Java 类加载机制(JVM 将类的信息动态添加到内存并使用的一种机制)不那么反感了——这个还怎么说还是很神奇的。

也许学习就应该是这样,只要你敢于挑战自己,就能收获知识——就像山就在那里,只要你肯走那么路就在脚下。

还有就是说我我这呢还有一些关于这方面的一些资料那么有需要的小伙伴就可以私信我哈

安卓应用热修复技术深度剖析:原理、实践与前沿发展 安卓应用热修复技术解析与实践指南 热修复技术通过动态加载补丁包,无需重新发布APK即可修复线上Bug或更新功能,解决了传统更新方式用户参与度低、周期长的问题。其核心原理基于修改类加载机制,主流策略分为即时生效(替换方法指针,兼容性差)和重启生效(重构类加载链,如Tinker的合成Dex方案)。资源修复则通过反射替换AssetManager实现。 主流框架如Tinker(稳健合成Dex)、Robust(插桩动态切换)各有侧重,需根据业务需求选择。实践中需注意多进程适配、ProGuard规则对齐等问题。 阅读详情

相关推荐

FPGA高速通信双核解析:CMAC与Interlaken硬核的实战对比

本文深入对比了FPGA中两大高速通信硬核CMAC与Interlaken的核心差异与应用场景。CMAC作为标准以太网接入方案,适用于网卡、交换机等需对外互联的场景;而Interlaken则以极低延迟和高效通道化能力,专为芯片间、板间裸数据高速传输设计。文章通过实战案例与性能指标分析,为FPGA高速通信方案选型提供清晰指南。

f9g0h的博客 846

我竟然不再抗拒 Java 的类加载机制了

01、字节码在聊 Java 类加载机制之前,需要先了解一下 Java 字节码,因为它和类加载机制息息相关。 计算机只认识 0 和 1,所以任何语言编写的程序都需要编译成机器码才能被计算机理解,然后执行,Java 也不例外。www.81rz.com/ksjc195/Java 在诞生的时候喊出了一个非常牛逼的口号:“Write Once, Run Anywhere”,为了达成这个目的,Sun 公司发布...

146

NFS共享速度慢?麒麟系统性能调优5个关键参数实测对比

本文针对银河麒麟服务器系统上NFS共享速度慢的问题,通过实测对比分析了五个关键调优参数。重点探讨了rsize/wsize传输块大小、TCP/UDP协议选择、sync/async模式权衡等,并结合麒麟系统特性提供了具体的优化建议与配置示例,旨在帮助用户有效提升国产化环境下的文件共享性能。

weixin_29254029的博客 338

解决idea编辑器中 bean 的加载

idea编辑器,解决Could not autowire. No beans of ‘Ilogin’ type found. more…问题。 打开设置 打开editor – > inspections. autowiring for bean class 去除勾。

wu135059的博客 1053

别再死磕GAN了!用PyTorch从零实现DDPM图像生成(附CIFAR-10完整代码)

本文详细介绍了如何使用PyTorch从零实现DDPM(Denoising Diffusion Probabilistic Models)图像生成模型,并在CIFAR-10数据集上进行训练和测试。通过对比GAN,DDPM展现出更稳定的训练过程和更高质量的生成效果。文章包含完整的代码实现、训练技巧和优化建议,帮助开发者快速掌握这一前沿的生成模型技术。

weixin_33720078的博客 631

Anaconda+清华源加速PyTorch GPU环境安装与CUDA版本匹配指南

深度学习环境管理常面临依赖冲突与下载缓慢问题,通过虚拟环境隔离与镜像源加速可显著提升效率。Anaconda利用conda机制创建独立Python环境,避免包版本冲突;清华源通过国内镜像同步大幅提高下载速度。GPU版PyTorch安装需严格匹配CUDA、cuDNN与显卡驱动版本,否则易出现CUDA不可用错误。该方案适用于图像分割、目标检测等需多版本PyTorch并存的场景,能快速搭建稳定GPU训练环境。本文详解Anaconda安装、清华源配置及PyTorch GPU版安装全流程。

weixin_30522983的博客 237

Java类的加载机制

1、加载的生命周期类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Intialization)、使用(Using)、卸载(Unloding)7个阶段。其中验证、准备、解析 3个部分统称为链接(Linking)。加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之

u010257931的博客 4001

华为交换机NAC配置避坑指南:搞定打印机、摄像头等哑终端接入(含MAC旁路认证)

本文详细解析华为交换机NAC配置中的MAC旁路认证方案,特别针对打印机、摄像头等哑终端接入问题提供避坑指南。通过对比传统模式与统一模式的配置差异,结合实际案例和典型错误排查,帮助网络工程师高效解决802.1X认证环境下的哑终端接入难题。

weixin_30338497的博客 442

一文搞懂Java类加载机制

初始化阶段是执行类构造器()方法的过程。

BarackYoung的博客 5431

RimWorld Mod开发避坑指南:从Defs命名规范到XML结构详解(附实战代码)

本文深入解析RimWorld Mod开发中Defs文件的编写规范与高级技巧,涵盖命名冲突预防、XML结构优化及高级功能实现。通过实战代码示例,帮助开发者避开常见陷阱,提升Mod兼容性与稳定性,特别适合RimWorld Mod开发者参考。

weixin_30790841的博客 453

Unity半透明物体景深失效?教你用双材质球方案完美解决(附完整Shader代码)

本文深入剖析了Unity中半透明物体导致景深效果失效的根本原因,即半透明物体默认不写入摄像机深度图。针对此问题,文章详细介绍了稳定高效的“双材质球”解决方案,通过为物体附加一个仅写入深度信息的不可见材质,完美修复景深效果,并提供了完整的Shader代码与实现脚本。

weixin_29010003的博客 384

手把手教你如何玩转Java基础面试题

下面的这些题目,主要是根据自己的亲身经历以及在学习的过程中碰到比较典型的内容,所以把这些进行整理,方便于更多的人进行学习和交流。 内容有点多,可能你会很反感,但是,我相信,如果你能认真的看完我这些,当你回头再回想整个Java内容的时候,你就会清晰很多。因为,这是自己的学习经历,我相信有很多的人跟自己都一样,所以,给点信心,别怕多,这么多学习干货,为什么要回避呢? 下面是其他方面...

Cs_hnu_scw的博客 1万+

安卓开发者必看:Win11最新Fastboot驱动安装避坑指南(含Android Bootloader Interface选择技巧)

本文为安卓开发者提供了Windows 11系统下Fastboot驱动安装的详细指南,特别针对Android Bootloader Interface选择技巧和多设备并发连接时的驱动冲突问题。通过解析Windows 11的特殊驱动验证机制,推荐使用Google官方USB驱动,并提供安装流程、版本选择建议及疑难问题排查方法,帮助开发者高效完成开发环境配置。

sea99的博客 1337

Java面试核心八股文与实战技巧

Java作为企业级开发的主流语言,其技术栈的深度和广度决定了面试考察的规律性。从JVM内存模型到Spring框架原理,再到分布式系统设计,这些核心技术构成了Java工程师的能力基石。理解GC机制、类加载原理、并发编程等底层概念,不仅能应对面试,更能提升解决实际问题的能力。在微服务和云原生架构盛行的当下,掌握Redis缓存策略、分布式ID生成等高频考点尤为重要。通过系统化整理八股文知识库,结合STAR法则描述项目经验,可以显著提升面试通过率。

weixin_34129696的博客 412

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

java ClassLoader笔记(一)

java ClassLoader笔记(一)

fbysss的专栏 1703

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

手把手教你如何玩转面试题(Java基础)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.youkuaiyun.com/Cs_hnu_scw/article/details/79635874 &nbsp; &nbsp; &nbsp; &nbsp; 下面的这些题目,主要是根据自己的亲身经历...

liyang_com的博客 664

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

在GitHub上超百万下载量的Java面试指南!惨遭大厂集体封杀

作为程序员,你反感面试的时候做题吗?有很多公司在面试中都会有让求职者现场做题的环节,尤其是与开发相关的岗位,比较常见。但是很多程序员却非常反感这件事。。。仅靠几个题目很难辨别出真实水平,如果仅凭这个来判定面试人员是否合格的话,未免有点武断。坦白来讲,笔试最初设置的目的是为了设置门槛,题目涉及的都是简单的算法和数据结构,另外,虽然题目与实际工作并无关系,但却可以考量一个人对待面试和岗位的态度,这些题目可能不能真正考察出你的实际能力,但是能帮助公司对你有一个初步的了解和认识,以及把握你对这个岗位的心仪程度。

m0_71777195的博客 114

2025华为Java岗面试高频考点与备战全攻略

Java技术面试是检验开发者基础功底与工程实践能力的关键环节,尤其在大厂招聘中,对JVM内存模型、并发编程、集合框架等底层原理的考察日益深入。理解这些核心概念不仅有助于应对面试中的连环追问,更能帮助开发者构建稳固的知识体系。在实际项目中,无论是排查线上性能问题,还是设计高并发缓存方案,都离不开对这些基础原理的灵活运用。从面向对象特性到Spring容器机制,从MySQL索引优化到Redis缓存一致性,再到手撕算法的实战演练,系统梳理各模块高频考点与答题思路,是高效备战技术面试的重要路径。本文聚焦Java后端方

weixin_34194087的博客 383

【转】 java ClassLoader笔记(一)

一、Sun JDK Classloader体系 1.层次关系 Bootstrap: 加载rt.jar 2.特殊点    Bootstrap ClassLoader为C++所写,Extension ClassLoader的parent为null,其中,getParent返回实例化本ClassLoader的ClassLoader,并不是superClas

SHUAI-优快云 423

Java进阶面试笔记:大厂JVM、并发与分布式系统设计

Java作为企业级开发的核心语言,其技术栈深度与工程实践能力是面试考察的重点方向。从JVM内存模型到并发编程的AQS机制,再到分布式系统的CAP理论,这些基础概念构成了Java技术体系的骨架。理解GC调优原理能有效解决OOM问题,掌握类加载机制可应对热部署等复杂场景,而并发容器的选型直接影响系统吞吐量。在分布式领域,Redis与ZK的锁实现差异、微服务链路追踪等技术,都是构建高可用架构的关键。本笔记通过大厂真实面试题解析,结合电商秒杀、分库分表等实战案例,系统梳理了Java进阶的核心考点与工程实践。

weixin_33483304的博客 264

Java全栈工程师面试核心考点与实战解析

Java全栈开发是当前企业级应用开发的主流技术方向,涉及从JVM底层原理到分布式系统设计的完整技术栈。理解JVM内存模型、类加载机制等核心原理是构建高性能应用的基础,而Spring生态的自动配置、事务管理等特性则大幅提升了开发效率。在数据库优化方面,索引策略与缓存应用直接影响系统吞吐量,需要掌握Redis高级特性如分布式锁实现。系统设计能力体现在应对高并发场景的架构决策,如秒杀系统中的流量削峰方案。工程实践层面,CI/CD流水线设计和ELK日志监控方案是DevOps能力的重要体现。本文通过典型面试题解析,帮

weixin_30582943的博客 363

java面试题(重点)

1 对类加载器的理解,委托机制的理解,加载出错在哪报错。 2 动态代理反射有什么关系。 3通过反射获得字节码的三种方式 4集合框架 list下面有哪些类,各自的特点,map的特点和下面有哪些子类和特点 5类与类,类与对象,类与接口的关系 6创建多线程的两种方式 7枚举是否可以继承类 8什么是反射。对暴力反射的理解 9遍历map的方式 10说说对线程池的理解 11说说字符流和字节

面朝大海,春暖花开 806

Java面试中那些易被忽略的细节与应对思路

你背诵“三级缓存,提前暴露对象引用”,接着就会被问:“为什么只能解决单例的循环依赖,prototype为什么不行?再比如@Transactional自调用失效,你能回答出“因为Spring的AOP代理在内部调用时不会经过代理对象”,可如果面试官再问“那怎么解决”,你除了自己注入自己,是否知道使用AopContext.currentProxy()?靠谱的做法是,简历里的每一项技术,你都能讲出三个层次:是什么,为什么这样设计,生产环境中哪里会踩坑。这种“总-分-例”的节奏,能让面试官瞬间抓住你的逻辑。

searchboy2025的博客 10

Java大厂面试深度解析:JVM、集合框架与Spring实战

Java虚拟机(JVM)作为Java生态的核心基石,其内存模型、类加载机制和垃圾回收原理是构建高并发应用的关键。以HashMap为代表的集合框架通过哈希算法和红黑树实现高效数据存取,而ConcurrentHashMap则采用CAS+synchronized优化并发性能。Spring框架通过三级缓存解决循环依赖问题,其事务传播机制在实际开发中需要特别注意边界条件。在分布式系统中,Redis分布式锁的实现需要考虑锁标识、可重入性和自动续期等进阶特性。理解这些核心技术原理,能够帮助开发者应对电商秒杀、实时数据处理

chuange6363的博客 384

Java工程师面试核心:JVM、并发、Spring与分布式系统解析

Java工程师面试的核心技术点通常围绕JVM底层原理、并发编程、Spring框架和分布式系统设计展开。JVM的类加载机制和GC调优是面试中的高频考点,尤其是实战中的内存泄漏分析和性能调优。并发编程中,ThreadLocal内存泄漏和AQS同步队列的竞争策略是常见陷阱,需要深入理解其原理和解决方案。Spring框架的隐藏考点包括Bean生命周期和事务传播机制,而分布式系统中的Redis持久化策略和分布式锁实现则是技术难点。掌握这些核心概念不仅能提升面试表现,还能在实际工程中优化系统性能。本文通过解析高频面试题

weixin_30435261的博客 429
上一篇: 现在计算机这个行业的技术更新换代怎么可以这么快(在不学点东西真的会被淘汰)
下一篇: 兄弟们这些java中的枚举你们知道?
在酒吧写代码
博客等级 码龄7年 211粉丝 330原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值