二、类加载、连接和初始化

1. 类从加载、连接、初始化,到卸载的生命周期及概述

在这里插入图片描述

  1. 加载:查找并加载 class 文件中的二进制数据

  2. 连接:将已读入内存的 class 文件的二进制数据合并到 JVM 运行时环境中去,包含如下几个步骤:

    1. 验证:确保被加载的类的正确性。

    2. 准备:为类的 静态变量 分配内存,并初始化它们。

      注意:这里的初始化就是设置默认值 0(引用变量则是 null)。

    3. 解析:把常量池中的符号引用转换成直接引用。

  3. 初始化:为类的 静态变量 赋初始化值

    注意:这里的初始值就是我们在源码中定义的初始值。

2. 类的加载

2.1 类加载要完成的功能

在类的加载阶段要完成的功能有:

  1. 通过类的全限定名来获取该类的 class 文件中的二进制字节流数据;

  2. 把二进制字节流数据转换为方法区的运行时数据结构(也就是说 类加载完成之后,就保存在方法区中了)。

  3. 在堆中创建一个 java.lang.Class 对象,用来 封装类在方法区中的数据结构,并向外提供了访问方法区内数据结构的接口

2.2 类加载的方式

  1. 最常见的方式:

    1. 从本地文件系统中加载;
    2. jar 等归档文件中加载;
  2. 动态的方式:

    1. java 源文件 动态编译class
  3. 其他方式:

    1. 从网络中下载;
    2. 从专有数据库中加载;

2.3 类加载器

2.3.1 Java 虚拟机自带的加载器(系统类加载器)

Java 虚拟机自带的加载器包括:

  1. 启动类加载器(BootstrapClassLoader);

  2. 平台类加载器(PlatformClassLoader);

    JDK 9 之后就将 JDK 8 中的扩展类加载器(ExtensionClassLoader)废除了,新增了平台类加载器。
    这是因为:

    1. 扩展类加载器不安全;

    2. JDK 9 之后新增的模块化开发完全可以代替扩展类加载器。

  3. 应用程序类加载器(AppClassLoader)。

2.3.1.1 启动类加载器(BootstrapClassLoader
  1. JDK 9 中:

    用于加载启动的基础模块类,比如:java.base、java.management、java.xml 等。
    (JDK 9 中新增了模块的概念)
    
  2. JDK 8 中:

    负责加载 <JAVA_HOME>/lib,或者 -Xbootclasspath 参数指定的路径下的,且是虚拟机识别的类库。
    (按照名字识别,比如 rt.jar。对于不能识别的文件不予装载)
    

如果一个类是通过启动类加载器加载出来的,那么该类对应的 Class 对象的 getClassCloader() 方法返回 null

2.3.1.2 平台类加载器(PlatformClassLoader
  1. JDK 9 中:

    用于加载一些平台相关的模块,比如:java.scripting、java.compiler*、java.corba* 等。
    (JDK 9 中新增了模块的概念)
    
  2. JDK 8 中:

    平台类加载器是在 JDK 9 中才提出来的,用于代替扩展类加载器。
    
2.3.1.3 扩展类加载器(ExtensionClassLoader
  1. JDK 9 中:

    扩展类加载器在 JDK 9 中已废除,被平台类加载器所取代。
    
  2. JDK 8 中:

    负责加载 <JRE_HOME>/lib/ext,或者 java.ext.dirs 系统变量所指定的路径下的所有类库。
    
2.3.1.4 应用程序类加载器(AppClassLoader
  1. JDK 9 中:

    用于加载应用级别的模块,比如:jdk.compiler、jdk.jartoor、jdk.jshell 等;
    (JDK 9 中新增了模块的概念)
    
    还用于加载 `classpath` 路径下的所有类库。
    
  2. JDK 8 中:

    负责加载 `classpath` 路径下的所有类库。
    
2.3.2 自定义类加载器

自定义类加载器就是用户自定义的加载器:

  1. 自定义类加载器是 java.lang.ClassLoader 的子类;
  2. 通过自定义类加载器用户可以定制类的加载方式;

注意:自定义类加载器的加载顺序在所有系统类加载器之后。

2.3.2.1 自定义类加载器举例

继承 ClassLoader 实现自定义类加载器时,推荐重写 findClass() 方法

在这里插入图片描述
在这里插入图片描述

由于 MyClass 类的 class 文件会自动在 bin/ 目录下生成(即在 AppClassLoaderclasspath 路径下),所以最终还是 AppClassLoader 来加载 MyClass

要想使用 MyClassLoader 来加载 MyClass 类,将 bin/ 目录下生成的 MyClass.class 删除即可。

2.3.3 类加载器之间的关系

在这里插入图片描述

2.3.4 注意事项
  1. 不能直接在 Java 程序中引用启动类加载器(即不能直接设置 ClassLoadernull)。

  2. 类加载器并不需要等到某个类 首次主动使用 时才加载它。

    JVM 规范允许类加载器在预料到某个类将要被使用的时候就预先加载它。

  3. 如果某个类的 class 文件在加载的时候缺失了,那么会在该类 首次主动使用 的时候才报 LinkageError 错误。

    如果一直没有被使用,那么就不会报该错误。

2.4 双亲委派模型

JVM 中的 ClassLoader 通常采用双亲委派模型。该模型要求除了启动类加载器外,其它的类加载器都应该有自己的父级加载器。

注意:这里的父子关系是组合,而不是继承。

双亲委派模块对于保证 Java 程序的稳定运作很重要。

实现双亲委派的代码在 java.lang.ClassLoaderloadClass() 方法中。

继承 ClassLoader 实现自定义类加载器时,推荐重写 findClass() 方法

2.4.1 双亲委派模型的工作过程

工作过程如下:

  1. 一个类加载器接收到类加载请求后,首先搜索它的内建加载器定义的所有 具名模块

  2. 如果找到了合适的模块定义,将会使用该加载器来加载;

  3. 如果 class 没有在这些加载器定义的 具名模块 中找到,那么将会委托给父级加载器(直到启动类加载器);

  4. 如果父级加载器反馈它不能完成加载请求,比如在它的搜索路径下找不到这个类,那么子的类加载器才自己来加载;

  5. 在类路径下找到的类将成为这些加载器的 无名模块

注意:JDK 8 中还不存在 模块 的概念,所以没有 “搜索内存加载器定义的具名模块” 这个步骤,也就是说 JDK 8 中不存在第 2 步。

即:JDK 8 中,子级加载器直接委托给父级加载器。

2.4.2 定义类加载器 & 初始类加载器

如果有一个类加载器能加载某个类,称为定义类加载器。

所有能成功返回该类的 class 的类加载器,都被称为初始类加载器。

2.4.3 注意事项
  1. 如果没有指定父加载器,默认就是启动加载器。

  2. 每个类加载器都有自己的命名空间,命名空间由该加载器及其所有父加载器所加载的类构成。

    不同的命名空间,可以出现类的全路径名相同的情况。

  3. 运行时包由同一个类加载器的类构成,决定两个类是否属于同一个运行时包,不仅要看全路径名是否一样,还要看定义类加载器是否相同。

    只有属于同一个运行时包的类才能实现相互包内可见。

2.4.4 破坏双亲委派模型 & 线程上下文类加载器

双亲委派模型存在这样一个问题:父加载器无法向下识别子加载器加载的资源。

为了解决这个问题,引入了线程上下文类加载器,可以通过 ThreadsetContextClassLoader() 方法进行设置。

另外一种典型情况就是实现热替换,比如 OSGI 的模块化热部署。它的类加载器就不再是严格按照双亲委派模型,很多可能就在平级
的类加载器中执行了。

3. 类的连接

3.1 验证

3.1.1 验证的主要内容

类连接时,验证的主要内容有:

  1. 类文件结构检查:按照 JVM 规范规定的类文件结构进行。

  2. 元数据验证:对字节码描述的信息进行语义分析,保证其符合 Java 语言规范要求。

  3. 字节码验证:通过对数据流和控制流进行分析,确保程序语义是合法、且符合逻辑。

    这里主要是对方法体进行校验。

  4. 符号引用验证:对类自身以外的信息,也就是常量池中的各种符号引用,进行匹配校验。

3.2 准备

为类的 静态变量 分配内存,并初始化它们。

注意:这里的初始化就是系统自动设置默认值 0(引用变量则是 null)。

3.3 解析(常量池中的符号引用转换成直接引用)

所谓解析,就是把常量池中的符号引用转换成直接引用的过程。其中:

  1. 符号引用:以一组无歧义的符号来描述所引用的目标。与虚拟机的实现无关。

  2. 直接引用:直接指向目标的指针、相对偏移量、或是能间接定位到目标的句柄。与虚拟机的实现有关。

解析主要是针对:类、接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符。

4. 类的初始化

类的初始化就是为类的静态变量赋初始值,或者说是执行类构造器 <clinit> 方法的过程。

这里的赋初始值指的是程序员在定义静态变量时(或者在静态代码块中)手动设置的初始值。

4.1 类初始化的过程

  1. 如果类还没有加载和连接,就先加载和连接。

  2. 如果类存在父类 ,且父类没有初始化,就先初始化父类。

  3. 如果类中存在初始化语句,就依次执行这些初始化语句。

  4. 如果是接口的话:

    1. 初始化一个类的时候,并不会先初始化它实现的接口。
    2. 初始化一个接口的时候,并不会先初始化它的父接口。
    3. 只有当程序首次使用接口里面的变量,或者调用接口方法时,才会导致接口的初始化。
  5. 调用 ClassLoader 类的 loadClass 方法加载一个类时,并不会初始化该类。(这不是对类的主动使用)

4.2 类初始化的时机(对类的首次主动使用)

Java 程序对类的使用方式分为:

  1. 主动使用;

  2. 被动使用。

类初始化的时机就是:JVM 必须在每个类或接口 首次主动使用 时才初始化它们。

被动使用类不会导致类的初始化。

4.2.1 主动使用的情况

主动使用类或接口的情况包括:

  1. 创建类实例;

  2. 访问某个类或接口的静态变量;

  3. 调用类的静态方法;

  4. 反射某个类;

  5. 初始化某个类的子类,而父类还没有初始化;

  6. JVM 启动的时候运行的主类;

  7. 定义了 default 方法的接口,当接口实现类初始化时。

4.2.2 被动使用的情况

被动使用类或接口的情况包括:

  1. 通过子类引用父类的静态字段,不会导致子类的初始化;

  2. 当定义类类型的空数组时,不会导致类的初始化。如 Foo[] foos = new Foo[3];

  3. 引用类的常量时(final static 修饰的成员变量),不会导致类的初始化。

4.2.3 举例说明

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5. 类的卸载

当代表一个类的 Class 对象不再被引用时,那么 Class 对象的生命周期就结束了。Class 对象对应的在方法区中的数据也会被卸载。

注意:

  1. JVM 自带的类加载器加载的类是不会被卸载的。

  2. 由自定义类加载器加载的类是可以卸载的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

自学网安-DNS

01DNS Domain Name Service域名服务 作用&#xff1a;为客户机提供域名解析服务器 02域名组成 2.1域名组成概述 如"www.sina.com.cn"是一个域名&#xff0c;从严格意义上讲&#xff0c;"sina.com.cn"才被称为域名(全球唯一)&#xff0c;而"www"…

finalshell连接linux的kali系统

kali的ssh服务似乎是默认关闭的&#xff0c;笔者在玩CentOS系统时可以直接用finalshell完成连接&#xff0c;但kali不行&#xff0c;需要先手动开启ssh服务。 开启kali的ssh服务 输入【ssh start】命令开启ssh服务&#xff0c;可以用【ssh status】命令查看ssh状态&#xff0c…

BL0942 内置时钟免校准计量芯片 用于智能家居领域 上海贝岭 低成本 使用指南

BL0939是上海贝岭股份有限公司开发的一款用于智能家居领域进行电能测量的专用芯片&#xff0c;支持两路测量&#xff0c;可同时进行计量和漏电故障检测&#xff0c;漏电检测电流可设&#xff0c;响应时间快&#xff0c;具有体积小&#xff0c;外围电路简单&#xff0c;成本低廉…

风丘车辆热管理测试方案

车辆热管理是在能源危机出现、汽车排放法规日益严格以及人们对汽车舒适性要求更高的背景下应运而生的。将各个系统或部件如冷却系统、润滑系统和空调系统等集成一个有效的热管理系统&#xff1b;控制和优化车辆的热量传递过程&#xff0c;保证各关键部件和系统安全高效运行&…

uniapp小程序实现自定义返回按钮和胶囊对齐 做到兼容各手机型号

效果&#xff1a; 用到的API&#xff1a; uni.getMenuButtonBoundingClientRect();官网地址&#xff1a; https://uniapp.dcloud.net.cn/api/ui/menuButton.html#getmenubuttonboundingclientrect 控制台打印&#xff1a; 代码示例&#xff1a; <template><view cl…

MNIST 数据集详析:使用残差网络RESNET识别手写数字(文末送书)

MNIST 数据集已经是一个几乎每个初学者都会接触的数据集, 很多实验、很多模型都会以MNIST 数据集作为训练对象, 不过有些人可能对它还不是很了解, 那么今天我们一起来学习一下MNIST 数据集&#xff0c;同时构建残差网络来识别手写数字。 1.MNIST 介绍 MNIST手写数字数据库具有…

Java 数据结构篇-实现红黑树的核心方法

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 红黑树的说明 2.0 红黑树的特性 3.0 红黑树的成员变量及其构造方法 4.0 实现红黑树的核心方法 4.1 红黑树内部类的核心方法 &#xff08;1&#xff09;判断当前…

微信小程序之WXSS模板样式、页面配置(.json)和网络数据请求

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

机器学习整理

绪论 什么是机器学习&#xff1f; 机器学习研究能够从经验中自动提升自身性能的计算机算法。 机器学习经历了哪几个阶段&#xff1f; 推理期&#xff1a;赋予机器逻辑推理能力 知识期&#xff1a;使机器拥有知识 学习期&#xff1a;让机器自己学习 什么是有监督学习和无监…

Go使用记忆化搜索的套路【以20240121力扣每日一题为例】

题目 分析 这道题很明显记忆化搜索&#xff0c;用py很容易写出来 Python class Solution:def splitArray(self, nums: List[int], k: int) -> int:n len(nums)# 寻找分割子数组中和的最小的最大值s [0]for num in nums:s.append(s[-1] num)#print(s)cachedef dfs(cur,…

WampServer

开发笔记 推荐链接php无法保存SESSION问题部署SSL时候产生的问题 推荐链接 链接目录 php无法保存SESSION问题 php.ini文件和phpForApache.ini 文件 里面都有 对路径的控制&#xff0c;相关路径问题可能也需要进行修改&#xff0c;打开文件搜索wamp64或wamp 就可以看到了&…

火山引擎ByteHouse:“专用向量数据库”与“数据库+向量扩展”,怎么选?

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 背景 随着LLM&#xff08;Large Language Model&#xff09;的不断发展&#xff0c;向量检索也逐渐成为关注的焦点。LLM通过处理大量的文本数据&#xff0c;获取丰…

第9章-网络设备基本调试

1. 网络连通性测试 ping命令 定义&#xff1a;基于ICMP协议开发的应用程序&#xff0c;检测网络连通性&#xff1b; 功能&#xff1a; ① 检测网络连接的状态&#xff1b; ② 检测目标计算机是否在线&#xff1b; ③ 定位故障排除&#xff1b; ④ 检测网络延迟和丢包情况&#…

c++QT文件IO

1、QFileDialog文件对话框 与QMessageBox一样&#xff0c;QFileDialog也继承了QDialog类&#xff0c;直接使用静态成员函数弹窗。弹出的结果&#xff08;选择文件的路径&#xff09;通过返回值获取。 1&#xff09;获取一个打开或保存的文件路径 // 获取一个打开或保存的文件路…

Linux:动静态库的概念制作和底层工作原理

文章目录 动静态库基础认知动静态库基本概念静态库的制作库的概念包的概念 静态库的使用第三方库小结 动态库的制作动态库的使用动态库如何找到内容&#xff1f;小结 动态库加载库和程序都要加载可执行程序的地址问题地址问题逻辑地址和平坦模式绝对编址和相对编址与位置无关码…

esxi配置NTP自动对时与手动对时

目录 背景解法配置NTP服务器立即与NTP服务器同步时间 附&#xff1a;几个常用的NTP服务器列表 背景 VMware ESXi 6.7运行了一段时间后偶然发现系统时间与标准时间有5分钟左右的差异&#xff0c;于是研究了下如何自动对时以及用命令行立即对时。 解法 配置NTP服务器 首先在管…

啥,ui叫我做一个移动端好看的轮播--异形的Slide

先看效果,得实现两边的缩放和无线滚动 实现方法 我的基础架构是 next.jsswiper 下载swiper包 yarn add swiper下载后在页面中引用 import { useEffect, useState } from "react"; import styles from "./index.module.css"; import Image from "n…

DataStream API(源算子)

目录 源算子 1&#xff0c;从集合中读取数据 2&#xff0c;从文件读取数据 3&#xff0c;从 Socket 读取数据 4&#xff0c;从 Kafka 读取数据 5&#xff0c;自定义源算子 6&#xff0c;Flink 支持的数据类型 6.1 Flink 支持多种数据类型&#xff0c;包括但不限于&…

一、认识 JVM 规范(JVM 概述、字节码指令集、Class文件解析、ASM)

1. JVM 概述 JVM&#xff1a;Java Virtual Machine&#xff0c;也就是 Java 虚拟机 所谓虚拟机是指&#xff1a;通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的计算机系统。 即&#xff1a;虚拟机是一个计算机系统。这种计算机系统运行在完全隔离的环境中…

Linux Centos7环境下安装Redis5

Centos7环境下安装Redis5 使用 yum 安装创建符号链接针对可执⾏程序设置符号链接针对配置⽂件设置符号链接 修改配置文件启动Redis停止Redis 一般情况下我们在 linux 系统中想要安装一些程序首先会想到使用 yum 源来安装, 但是在下图中我们可以看到 Redis 版本还是3.X的版本, 所…