Java类加载

news2024/11/25 4:49:20

类加载的时机

一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载、验证、准备、解析、初始化、使用和卸载七个阶段。其中验证、准备、解析三个阶段统称为连接。

未命名

图中加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类型的加载过程必须按照这种顺序开始,但是解析不一定,解析可能出现在初始化之后,这是为了适配Java动态绑定的特性。

Java虚拟机规范规定了有且只有6中情况下必须对类立即进行”初始化“:

  1. 遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类型没有进行过初始化,则需要先触发其初始化阶段。典型场景有:
    • 使用new 关键字实例化对象
    • 读取或设置一个类型的静态字段(被final修饰的、已在编译期把结果放入常量池的静态字段除外)
    • 调用一个类型的静态方法
  2. 使用java.lang.reflect包的方法对类型进行反射调用的时候
  3. 当初始化类时,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化
  4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的类),虚拟机会先初始化这个类
  5. 如果一个java.lang.invoke.MethodHandle实例最后的解析结果为REF_getStaticREF_putStaticREF_invokeStaticREF_newInvokeSpecial四种类型的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化
  6. 当一个接口中定义了默认方法时,如果有这个接口的实现类发生了初始化,那该接口要在其之前被初始化

类加载过程

加载

加载阶段是整个类加载过程的一个阶段。在加载阶段,Java虚拟机需要完成以下三件事情:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流
  2. 将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构
  3. 在内存中生成一个代表这个类的java.lang.Class对象

非数组类加载阶段既可以由Java虚拟机里内置的引导类加载器来完成,也可以由用户自定义的类加载器去完成。

数组类本身不通过类加载器创建,它是由Java虚拟机直接在内存中动态构造出来的。但数组类与类加载器依然有很密切的关系,数组类的元素类型最终还是要靠类加载器来完成加载。

验证

验证是连接阶段地第一步,这一步是为了确保Class文件的字节流中包含的信息符合Java虚拟机规范的全部约束要求。

字节码可以在语义上表达出来Java语言所做不到的危险操作,所以验证阶段十分重要。

验证阶段大致分为四个阶段

  1. 文件格式验证
    验证字节流是否符合Class文件格式规范
    是否以魔数0xCAFEBABE开头
    主、次版本号是否在当前Java虚拟机接受范围之内
  2. 元数据验证
    对字节码描述的信息进行语义分析
    这个类是否有父类
    这个类是否集成了不允许被继承的类
    这个类是否实验写其父类或接口中要求实现的方法
  3. 字节码验证
    通过数据流分析和控制流分析,确定程序语义是否合法、是否符合逻辑。
  4. 符号引用验证
    对类自身以外的各种信息进行匹配性校验

准备

正式为类中定义的变量(即静态变量)分配内存并设置类变量初始值。

解析

Java虚拟机将常量池内的符号引用替换为直接引用。

  • 符号引用:以一组符号来描述所引用的目标,符号可以是任意形式的字面量,只要使用时能无歧义地定位到目标即可
  • 直接引用:可以使直接指向目标的指针、相对偏移量或者是一个能间接定位到目标的句柄

初始化

执行类构造器 <cinit>() 方法的过程。

<cinit>()方法是由编译期自动收集类中所有类变量赋值动作和静态语句块中的语句合并产生的,收集顺序和在类中的定义顺序相同,所以静态语句块只能访问到定位在它之前的静态变量,定义在它之后的变量可以对其赋值,但是不能访问。

public class Test {
    static {
        i = 0; // 可以编译通过
        System.out.println(i);  // 提示非法向前引用
    }
    static int i;
}

类加载器

类加载器的作用就是“通过一个类的全限定名来获取描述该类的二进制字节流”。

类与类加载器

比较两个类是否“相等”,只有在两个类是由同一个类加载器加载的前提下才有意义,否则,即使两个类来源于同一个Class文件,被同一个Java虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。

import java.io.IOException;
import java.io.InputStream;

public class ClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        ClassLoader myLoader = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException{
                try{
                    String fileName = name.substring(name.lastIndexOf(".")+1)+".class";
                    InputStream is = getClass().getResourceAsStream(fileName);
                    if(is == null) {
                        return super.loadClass(name);
                    }
                    byte[] b = new byte[is.available()];
                    is.read(b);
                    return defineClass(name, b, 0, b.length);
                } catch (IOException e) {
                    throw new ClassNotFoundException(name);
                }
            }
        };

        Object obj = myLoader.loadClass("ClassLoaderTest").newInstance();
        System.out.println(obj.getClass());
        System.out.println(obj instanceof ClassLoaderTest);
    }
}

运行结果
image-20230416153930443

双亲委派模型

  • 启动类加载器(Bootstrap Class Loader):这个类加载器由c++编写,是虚拟机的一部分,一般负责加载<JAVA_HOME>\lib目录下的能被Java虚拟机识别的类库。
  • 扩展类加载器(Extension Class Loader):这个类加载器是以Java代码的形式实现的,负责加载<JAVA_HOME>\lib\ext 目录的类库
  • 应用程序加载器(Application Class Loader):负责加载用户类路径上所有的类库,这个也是程序中默认的类加载器

双亲委派模型:如果一个类加载器收到了类加载的请求,它首先自己不会尝试加载这个类,而是把这个请求委派给父类加载器去完成。只有当父加载器反馈复发完成这个加载请求(它的搜索范围内没有找到所需的类)时,子加载器才会尝试自己去加载完成。

破坏双亲委派模型

双亲委派模型不是强制约束的模型,而是Java设计者推荐给开发者门的类加载器实现方式。所以有可能破坏双亲委派模型。如果用户覆盖了loadClass()方法,也就是双亲委派机制实现的具体位置,那么类加载不会按照双亲委派模型来进行。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CDGP数据治理专家认证含金量如何?值得考一个吗?

CDGP&#xff08;Certified Data Governance Professional&#xff09;数据治理专家认证的含金量非常高。该认证证明了持有人拥有数据治理方面的专业知识和技能&#xff0c;能够有效地管理和保护组织的数据资产。 CDGP认证考试内容涵盖数据治理的各个方面&#xff0c;包括数据…

看这家在线教育企业如何通过DHTMLX Scheduler,实现培训管理系统优化

“我们公司目前有一套培训管理系统&#xff0c;用于管理培训学员。目前学员越来越多&#xff0c;老旧的系统已经没法满足需求&#xff0c;导致我们经常需要手动记录学员出勤培训情况&#xff0c;除此之外&#xff0c;系统课程安排只展示时间&#xff0c;没法展示诸如主题&#…

macOS Big Sur 11.7.6 (20G1231) 正式版 ISO、PKG、DMG、IPSW 下载

本站下载的 macOS 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安装。另外也支持在 Windows 和 Linux 中创建可引导介质。 2023 年 4 月 10 日&#xff08;北京…

【Vue全家桶】Pinia状态管理

【Vue全家桶】Pinia状态管理 文章目录【Vue全家桶】Pinia状态管理写在前面一、认识Pinia1.1 认识Pinia1.2 为什么使用Pinia&#xff1f;二、 Store2.1 定义Store2.2 Option对象2.3 setup函数2.4 使用定义的Store三、Pinia核心概念State3.1 定义State3.2 操作State3.3 使用选项式…

基于小生境粒子群优化算法的考虑光伏波动性的主动配电网有功无功协调优化(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

C语言基础——指针

文章目录一、指针1.指针的意义2.指针类型表示3.一些操作3.1打印1个变量地址3.2通过地址查看改地址的内容以及修改改地址的内容3.3操作某个空间 -- 4个字节,给他赋值为100&#xff0c;只知道该空间的地址0x8000 00004.指针变量的定义5.指针类型的大小6.指针变量的使用6.1 指针变…

python数据分析-matplotlib折线图知识总结01

python绘图库matplotlib的知识总结一.matplotlib是什么二.matplotlib的安装与导入三.matplotlib的常用函数四.matplotlib绘制折线图的使用方法1.设置图形大小2. 利用数据绘图3.调整x,y轴的刻度,旋转角度,显示描述信息,绘制网格,添加图例4.图形的样式5.绘制多条折线6.显示绘制的…

python知识记录:灵活使用numpy提高python数据分析效率!

NumPy是Python语言的一个第三方库&#xff0c;其支持大量高维度数组与矩阵运算。 作为python科学计算领域的三剑客之一&#xff0c;numpy在数据分析处理方面有着独特的魅力&#xff01; numpy模块的出现更多的是在数组处理的操作上面&#xff0c;并且支持和python常用的数据结…

Transformer在时序预测的应⽤第一弹——Autoformer

Transformer在时序预测的应⽤第一弹——Autoformer 原文地址&#xff1a;Autoformer: Decomposition Transformers with Auto-Correlation for Long-Term Series Forecasting&#xff08;NIPS 2021&#xff09; 做长时间序列的预测 Decomposition把时间序列做拆分&#xff0c…

目标检测——YOLOv7(十三)

简介&#xff1a; 继美团发布YOLOV6之后&#xff0c;YOLO系列原作者也发布了YOLOV7。主要从两点进行模型的优化&#xff1a;模型结构重参化和动态标签分配。 YOLOv7的特点是快&#xff01;相同体量下比YOLOv5精度更高&#xff0c;速度快120%&#xff0c;比YOLOX快180%。 Github…

RabbitMQ消息丢失的情况,以及如何通过代码解决

目录 RabbitMQ消息丢失问题&#xff1a; 代码部分&#xff1a; 完整代码&#xff1a; RabitMQConfig&#xff1a; CourseMQListener: 生产者跟交换机通信的消息丢失解决 &#xff1a; 交换机跟消息队列的消息丢失&#xff1a; 消息队列跟消费者的消息丢失&#xff1a; …

自动处理【支付宝交易支付投诉管理系统】配置指南

大家好&#xff0c;我是小悟 已经有小伙伴开始使用自动处理【支付宝交易支付投诉管理系统】&#xff0c;所以详细介绍一下如何配置。 阅读这篇文章之前&#xff0c;结合这篇【连夜干出来一个自动处理【支付宝交易支付投诉管理系统】&#xff0c;支持多商户】干货食用更佳。 连…

Filter 过滤器 Listener 监听器

Filter web中的过滤器当用户访问服务器资源时&#xff0c;过滤器将请求拦截下来&#xff0c;完成一些通用的操作应用场景如&#xff1a;登录验证、统一编码处理、敏感字符过滤 编写filter对目标资源servlet进行拦截 1. 编写java类&#xff0c;实现filter接口 public class Qu…

智慧医院人员定位系统解决方案,助力医院安全管理智能化

随着经济的发展与生活质量的提升&#xff0c;人们对医疗健康的重视度越来越高&#xff0c;医疗行业也因此蓬勃发展起来。然而&#xff0c;不断扩大的经营规模也给医院安全管理带来挑战和难题。 医院安全管理痛点 1、医疗事件信息获取不及时甚至存在瞒报现象&#xff0c;管理者…

yc博客项目创建-白手起家

初始化项目 1、码云创建代码库 2、下载码云项目到本地 3、IDEA直接生成springboot项目 接入mysql 1、配置文件 2、代码配置 启动项目 访问项目 访问连接&#xff1a; http://localhost:8089/yc-blog/index/listlistContent 注意点&#xff1a;server.servlet.context-path…

Redis用于全局ID生成器、分布式锁的解决方案

全局ID生成器 每个店铺都可以发布优惠卷 当用户抢购时&#xff0c;就会生成订单并保存到tb_voucher_order这张表中&#xff0c;而订单表如果使用数据库自增id就存在一些问题&#xff1a; 1.id的规律性太明显 2.受单表数据量的限制 全局ID生成器&#xff0c;是一种在分布式系…

极光笔记 | 如何在Shopify中使用EngageLab (下)

Sendgird发布的《2022 Global Messaging Engagement Report》中揭示了世界各地的用户更喜欢用哪种方式与品牌互动&#xff0c;结论是&#xff1a;“电子邮件仍然是第一名&#xff08;短信紧随其后&#xff09;”。4800多名受访者中&#xff0c;有18%的人将电子邮件列为他们最常…

普通人是否能从ChatGPT中分一杯羹?

ChatGPT3.0刚刚推出&#xff0c;最开始的时候&#xff0c;人们只是将ChatGPT看作一个很会聊天的机器人&#xff0c;无论问题多么天马行空&#xff0c;它的答案看上去都有理有据。后来&#xff0c;像打开潘多拉魔盒一样&#xff0c;很多人开始拿它编大纲、撰写文案、编代码、创作…

Docker本地推送到hub,以及上传时遇到的问题解决

1.在本地创建一个 Dockerfile FROM ubuntu:latest RUN apt-get update && apt-get install -y curl CMD ["curl", "https://www.baidu.com"]2.在本地构建 Docker 镜像 在创建本地docker镜像的时候[TAG] .和[TAG] /PATH/TO 需要注意dockerfile文件…

ATTCK v12版本战术介绍——防御规避(二)

一、引言 在前几期文章中我们介绍了ATT&CK中侦察、资源开发、初始访问、执行、持久化、提权战术、防御规避&#xff08;一&#xff09;理论知识及实战研究&#xff0c;本期我们为大家介绍ATT&CK 14项战术中防御规避战术&#xff08;二&#xff09;&#xff0c;包括防御…