关于Java的类加载机制

news2024/12/23 15:41:57

1、概述

        类会在运行期间第一次使用时,被类加载器动态加载至JVM。JVM不会一次性加载所有类。因为如果一次性加载,会占用很多的内存。

2、类的生命周期

 

类的生命周期包括以下 7 个阶段:

  • 加载(Loading)
  • 验证(Verification)
  • 准备(Preparation)
  • 解析(Resolution)
  • 初始化(Initialization)
  • 使用(Using)
  • 卸载(Unloading)

2.1类的加载过程

包含:加载、验证、准备、解析和初始化 ,一共包括5 个阶段。

2.1.1加载

(1)加载过程

  1. 通过类的完全限定名称获取定义该类的二进制字节流
  2. 将该字节流表示的静态存储结构转换为Metaspace元空间区的运行时存储结构。
  3. 在内存中生成一个代表该类的 Class 对象,作为元空间区中该类各种数据的访问入口。

(2)二进制字节流获取方式

  • 从 ZIP 包读取,成为 JAR、EAR、WAR格式的基础。
  • 从网络中获取,最典型的应用是 Applet。
  • 运行时计算生成,例如动态代理技术,在 java.lang.reflect.Proxy 使用 ProxyGenerator.generateProxyClass 的代理类的二进制字节流。
  • 由其他文件或容器生成,例如由 JSP 文件生成对应的 Class 类。

2.1.2验证

确保 Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

2.1.3准备

使用的是元空间区的内存,为类变量(被 static 修饰的变量)分配内存并设置初始值。

实例变量不会在这阶段分配内存,它会在对象实例化时,随着对象一起被分配在堆中。

注意:根据不用类型初始值不同,int初始值一般为 0 值。

例如:下面的类变量 value 被初始化为 0 而不是 123

public static int value = 100;

如果类变量是常量,那么它将初始化为表达式所定义的值而不是 0。

public static final int value = 123;

2.1.4解析 

 将常量池的符号引用替换为直接引用的过程。其中解析过程在某些情况下可以在初始化阶段之后再开始,这是为了支持 Java 的动态绑定。

2.1.5初始化

初始化阶段是虚拟机执行类构造器 <clinit>()方法的过程。准备阶段,类变量已赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。

<clinit>()是由编译器自动收集类中所有类变量的赋值动作静态代码块中的语句合并产生的,编译器收集的顺序与源文件顺序一致。

所以,静态语句块只能访问定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问

public class Test {
    static {
        i = 0;                // 给变量赋值可以正常编译通过
        System.out.print(i);  // 这句编译器会提示“非法向前引用”
    }
    static int i = 1;
}

父类的 <clinit>() 方法先执行,也就意味着父类中定义的静态语句块的执行要优先于子类 。

在接口中有类变量初始化的赋值操作,因此接口与类一样都会生成 <clinit>() 方法,但接口中不可以使用静态语句块。接口与类不同的是,执行接口的 <clinit>() 方法不需要先执行父接口的 <clinit>() 方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的 <clinit>() 方法。

此外一个类的 <clinit>() 方法是线程安全的。多个线程同时初始化一个类,只会有一个线程执行这个类的 <clinit>() 方法,其它线程都会阻塞等待,直到活动线程执行 <clinit>() 方法完毕。

3、类加载的时机

3.1主动引用

虚拟机规范中并没有强制约束何时进行加载,但是严格规定了下列六种情况必须对类进行加载:

3.1.1遇到特殊指令时

演示需要类

class Prent{
    static int A = 23;
    static final int VALUE = 10;
    static {
        System.out.println("Prent被加载");
    }
    public static void dosth(){};
}
class Son extends Prent{
    static {
        System.out.println("Son被加载");
    }
}

(1)当 jvm 执行 new指令时会加载类。即:当程序创建一个类的实例对象

public class Demo01 {
    public static void main(String[] args) {
        // new
        Prent p = new Prent();
}

(2)当 jvm 执行 getstatic指令时会加载类。即:程序访问类的静态变量(不是静态常量,常量会被加载到运行时常量池)

// getstatic
System.out.println(Prent.A);

(3)当 jvm 执行 putstatic指令时会加载类。即:程序给类的静态变量赋值。

        // putstatic
        Prent.A = 188;

(4) 当 jvm 执行 invokestatic指令时会加载类。即:程序调用类的静态方法。

// invokestatic
        Prent.dosth();

 3.1.2反射

使用 java.lang.reflect包的方法对类进行反射调用时如 Class.forname("..."), 或newInstance() 等等。如果类没初始化,需要触发类的加载。

3.1.3继承

加载一个类,如果其父类还未加载,则先触发该父类的加载。

3.1.4main方法所在类

当虚拟机启动时,用户需要定义一个要执行的主类 ,虚拟机先加载这个类。

3.1.5接口实现

当一个接口中定义了 JDK8 新加入的默认方法(被 default 关键字修饰的接口方法)时,如果有这个接口的实现类发生了加载,则该接口要在实现类之前被加载

3.2被动引用

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

(1)通过子类引用父类的静态字段,不会导致子类加载。

System.out.println(Son.A);

(2)数组类型

通过数组定义来引用类,不会触发此类的加载。该过程会对数组类进行加载,数组类是一个由虚拟机自动生成的、直接继承自 Object 的子类,其中包含了数组的属性和方法。

//array继承自object与Prent无继承关系
Prent[] array = new Prent[10];

(3)类中常量

常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类

System.out.println(Prent.VALUE);

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

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

相关文章

关于软件的功能复用

有一些人总在说软件要复用&#xff0c;开发一个项目时要想想怎么在另一个项目中能重用。你问他怎么做到复用&#xff0c;就会听到微服务、中台一些名词 复用的层次 说到复用&#xff0c;首先要想明白复用的是啥 级别越低&#xff0c;粒度越小&#xff0c;复用的范围越广&#…

实现div的height从0到auto的过渡效果

通过修改max-height打到高度自适应的过程。 展开状态 收起状态 一般场景描述需求&#xff08;与项目业务无关&#xff09;&#xff1a; 需要完成一种过渡效果,即height是变化的&#xff0c;但不是数字到数字的变化&#xff0c;因为不知道展开之后的高度到底是多少?不确定!!!。…

Qt加载本地图片转为YUV420P格式数据

一、背景介绍 在流媒体应用中&#xff0c;视频编码是必不可少的一环。视频编码的作用是将高带宽、高码率的原始视频流压缩成低带宽、低码率的码流&#xff0c;以便于传输和存储。H264是一种高效的视频编码标准&#xff0c;具有良好的压缩性能和广泛的应用范围&#xff0c;在实…

《C++ primer》练习3.20:输出vector相邻元素的和输出vector头尾对象的和

最近看《C primer》&#xff0c;有这样一个题目 输出vector相邻元素的和 读入一组整数并把它们存入一个vector对象&#xff0c;将每对相邻整数的和输出出来。 这里要注意输入的奇数个和偶数个的数的区别。偶数个整数的话刚好数全部用完&#xff0c;奇数个整数最后一个数空出来…

淘宝平台开放接口API接口

淘宝平台开放接口API接口是指淘宝平台提供给第三方开发者的一组接口&#xff0c;用于实现与淘宝平台的数据交互和功能扩展。通过API接口&#xff0c;第三方开发者可以获取淘宝平台上的商品信息、订单信息、用户信息等数据&#xff0c;也可以实现商品的发布、订单的创建和支付等…

【图解RabbitMQ-7】图解RabbitMQ五种队列模型(简单模型、工作模型、发布订阅模型、路由模型、主题模型)及代码实现

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;CSDN实力新星&#xff0c;后端开发两年经验&#xff0c;曾担任甲方技术代表&#xff0c;业余独自创办智源恩创网络科技工作室。会点点Java相关技术栈、帆软报表、低代码平台快速开…

2023年世界机器人大会回顾

1、前记&#xff1a; 本次记录是我自己去世界机器人博览会参观的一些感受&#xff0c;所有回顾为个人感兴趣部分的机器人产品分享。整个参观下来最大的感受就是科学技术、特别是机器人技术和人工智能毫无疑问地、广泛的应用在我们日常生活的方方面面&#xff0c;在安全巡检、特…

【洛谷算法题】P5704-字母转换【入门1顺序结构】

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5704-字母转换【入门1顺序结构】&#x1f30f;题目描述&#x1f30f;输入格式&a…

ClickHouse进阶(十三):Clickhouse数据字典-3-文件数据源及Mysql数据源

进入正文前&#xff0c;感谢宝子们订阅专题、点赞、评论、收藏&#xff01;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; &#x1f3e1;个人主页&#xff1a;含各种IT体系技术,IT贫道_大数据OLAP体系技术栈,Apache Doris,Kerberos安全认证-CSDN博客 &#x1f4cc;订阅…

metinfo __ 6.0.0 __ file-read

metinfo __ 6.0.0 __ file-read 说明内容漏洞编号–漏洞名称MetInfo 6.0.0 任意文件读取漏洞漏洞评级高危影响范围6.0.0.0漏洞描述MetInfo 存在任意文件读取漏洞&#xff0c;攻击者利用该漏洞&#xff0c;在具有权限的情况下&#xff0c;可以读取网站任意文件&#xff0c;包括…

ASP.NET+sqlserver公司项目管理系统

一、源码描述 这是一款简洁十分美观的ASP.NETsqlserver源码&#xff0c;界面十分美观&#xff0c;功能也比较全面&#xff0c;比较适合 作为毕业设计、课程设计、使用&#xff0c;感兴趣的朋友可以下载看看哦 二、功能介绍 该源码功能十分的全面&#xff0c;具体介绍如下&…

centos定期清理磁盘

centos/linux定期清理磁盘 要定时清理空间&#xff0c;我们需要了解一个命令&#xff0c;find 命令&#xff0c;这个命令可以查询目录下特定文件名&#xff0c;生成日期的文件 小白教程&#xff0c;一看就会&#xff0c;一做就成。 1.查找需要删除的 find /data_back/zhhyba…

buuctf crypto 【Cipher】解题记录

1.打开题目就有密文 2.一点思路没有&#xff0c;看看大佬的wp&#xff08;BUUCTF Cipher 1_cipher buuctf_玥轩_521的博客-CSDN博客&#xff09;&#xff0c;捏麻麻的原来玄机就在“公平的玩吧”这句话里&#xff0c;playfair也是一种加密方式&#xff0c;密钥猜测也是playfair…

SMB 协议详解之-NTLM身份认证

前面的文章说明了SMB协议交互的过程,在SMB交互的Session Setup Request/Response会对请求者的身份进行验证,这其中涉及到两个主要的协议NTLM以及Kerberos,本文将对NTLM协议进行详细的说明。 什么是NTLM NTLM是 NT LAN Manager (NTLM) Authentication Protocol 的缩写,主要…

MediaCodec源码分析 configure流程

前言 本文梳理MediaCodec configure流程,基于7.0代码,这里只分析AVC和HEVC的视频硬解,流程图如下。 代码见: frameworks/base/media/java/android/media/MediaCodec.java frameworks/base/media/jni/android_media_MediaCodec.h frameworks/base/media/jni/android_media_…

C#,数值计算——指数微分(exponential deviates)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 指数偏差 /// Structure for exponential deviates. /// </summary> public class Expondev : Ran { private double beta { get; set; } /// <s…

windows或者任何系统通过二进制安装最新的Protocol Buffer Compiler

此处使用二进制法安装,适用于任何操作系统 安装预编译的二进制文件&#xff08;任何操作系统&#xff09; 要从预编译的二进制文件安装最新版本的协议编译器&#xff0c;请按照以下说明操作&#xff1a; 1.从 github.com/google/protobuf/releases 手动下载与您的操作系统和计…

学习 [Spring MVC] 的JSR 303和拦截器,提高开发效率

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《推荐】Spring与Mybatis集成整合》 ⛺️ 生活的理想&#xff0c;不断更新自己 ! 1.JSR303 1.1JSR303是什么 JSR 303是Java规范请求&#xff08;Java Specification Request&#xff09;…

【AI理论学习】语言模型Performer:一种基于Transformer架构的通用注意力框架

语言模型Performer&#xff1a;一种基于Transformer架构的通用注意力框架 Performer论文解读Regular Attention MechanismFAVOR&#xff1a;通过矩阵相关性实现快速注意力 Attention的时间复杂性绕过softmax瓶颈通过Gaussian kernel求Softmax kernel寻找更稳定的Softmax内核使用…

单链表(Single Link Table)——单文件实现

一、单链表前言 上篇文章我们讲述了顺序表&#xff0c;认真学习我们会发现顺序表优缺点。 缺点1&#xff1a;头部和中部的插入删除效率都不行&#xff0c;时间和空间复杂度都为O(N); 缺点2&#xff1a;空间不够了扩容有一定的消耗(尤其是realloc的异地扩容)&#xff1b; 缺…