Java中的类你了解多少(每日一练)

news2024/11/27 8:44:27

文章目录

  • 类的加载方式
  • 类的加载流程
  • 类的生命周期
    • 加载
    • 验证
    • 准备
    • 解析
    • 初始化
    • 类的销毁
  • 类加载器有哪些
  • 什么是双亲委派模型?

类的加载方式

  开发工具可以将java源代码编译为class字节码,类加载器加载class字节码,将字节码中的内容分配到内存中, jvm内存的分区如下:
在这里插入图片描述

类加载有三种⽅方式:

  1. 命令⾏行启动应用时候由JVM初始化加载
  2. 通过Class.forName()方法动态加载
  3. 通过ClassLoader.loadClass()⽅法动态加载

class.forNameclassLoader都可⽤来对类进行加载,现在做如下测试:

  1. 先定义一个Employee类为测试做准备
public class Employee {

    static {
        System.out.println("正在使⽤用静态初始化");
    }

    public Employee() {
        System.out.println("构造⽅法正在执⾏");
    }
}
  1. 使用ClassLoader.loadClass()方法动态加载
public class TestMain {
    public static void main(String[] args) throws Exception {
        System.out.println("begin classloader");
        //获取到加载器器
        ClassLoader loader = TestMain.class.getClassLoader();
        System.out.println(loader);
        //使用类加载器加载Employee对象
        Class<?> c = loader.loadClass("com.reminis.bean.Employee");
        System.out.println("after classloader");

        System.out.println("before newInstance... ");
        Employee info1 =(Employee) c.newInstance();
        System.out.println("after newInstance... ");
    }
}

/**
 * 程序执行结果:
 *     begin classloader
 *     sun.misc.Launcher$AppClassLoader@18b4aac2
 *     after classloader
 *     before newInstance...
 *     正在使⽤用静态初始化
 *     构造⽅法正在执⾏
 *     after newInstance...
 */

  1. 使用class.forName()测试:
public class TestMain {
    public static void main(String[] args) throws Exception {
        System.out.println("begin class.forName()");
        Class<?> clazz = Class.forName("com.reminis.bean.Employee");
        System.out.println("after class.forName()");

        System.out.println("before newInstance... ");
        Employee instance = (Employee) clazz.newInstance();
        System.out.println("after newInstance... ");
    }
}

/**
 * 程序执行结果:
 *      begin class.forName()
 *      正在使⽤用静态初始化
 *      after class.forName()
 *      before newInstance...
 *      构造⽅法正在执⾏
 *      after newInstance...
 *
 */
  1. 由上面两个程序的运行结果可知区别如下:
    • Class.forName()将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块;
    • ClassLoader.loadClass()只干⼀一件事情,就是将.class⽂件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
    • 注意: Class.forName(name, initialize, loader)带参函数也可控制是否加载static块。并且只有调⽤了newInstance()⽅法采⽤调用构造函数,创建类的对象 。

类的加载流程

  类的加载指的是将类的.class⽂件中的⼆进制数据读入到内存中,将其放在运行行时数据区的⽅方法区内,然后在堆区创建⼀个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中 的Class对象,Class对象封装了类在⽅法区内的数据结构,并且向Java程序员提供了了访问⽅法区内的数据结构的接口。
在这里插入图片描述
  类加载器并不需要等到某个类被“⾸次主动使用”时再加载它,JVM规范允许类加载器器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)如果这个类一直没有被程序主动使⽤,那么类加载器就不会报告错误。

加载.class文件的方式:

  1. 从本地系统中直接加载
  2. 通过⽹络下载.class文件
  3. 从zip,jar等归档文件中加载.class文件
  4. 从专有数据库中提取.class文件
  5. 将Java源文件动态编译为.class文件

类的生命周期

在这里插入图片描述

其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。

在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,⽽解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始。⽐如:动态绑定或晚期绑定。

注意:这里的⼏个阶段是按顺序开始,⽽不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在⼀个阶段执行的过程中调⽤或激活另一个阶段。

加载

加载主要指:查找并加载类的二进制数据。

  1. 通过一个类的全限定名来获取其定义的⼆进制字节流。
  2. 将这个字节流所代表的静态存储结构转化为⽅法区的运行时数据结构。
  3. 在Java堆中生成⼀个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入⼝。

相对于类加载的其他阶段⽽言,加载阶段(准确地说,是加载阶段获取类的⼆进制字节流的动作)是可控性最强的阶段,因为开发⼈员既可以使⽤系统提供的类加载器来完成加载,也可以自定义⾃⼰的类加载器来完成加载。

验证

验证的目的:确保被加载的类的正确性。 验证是为了确保Class⽂件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全.

验证内容为:

  1. ⽂件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
  2. 元数据验证:对字码描述的信息进⾏语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。
  3. 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
  4. 符号引⽤验证:确保解析动作能正确执行。

验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采⽤-Xverifynone参数来关闭⼤部分的类验证措施,以缩短虚拟机类加载的时间。

准备

准备⽬的:为类的静态变量分配内存,并将其初始化为默认值。准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。

  1. 这时候进行内存分配的仅包括类变量(static),⽽不包括实例变量,实例变量会在对象实例化时随着对象⼀块分配在Java堆中。
  2. 这⾥所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),⽽不是被在Java代码中被显式地赋予的值。
public static int value = 10//value在准备阶段过后的初始值为0,⽽不是10.
//value赋值为10的动作将在初始化阶段才会执⾏。

解析

把类中的符号引⽤转换为直接引⽤。

解析阶段是虚拟机将常量池内的符号引⽤替换为直接引⽤的过程,解析动作主要针对类或接⼝、字段、类⽅法、接⼝方法、⽅法类型、⽅法句柄和调用点限定符7类符号引⽤用进行。符号引⽤就是⼀组符号来描述⽬标, 可以是任何字⾯量。

直接引用就是直接指向目标的指针、相对偏移量或⼀个间接定位到目标的句柄。

初始化

初始化,为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。在Java 中对类变量进行初始值设定有两种方式:

  1. 声明类变量时指定初始值
  2. 使⽤静态代码块为类变量指定初始值

jvm初始化的步骤:

  1. 假如这个类还没有被加载和连接,则程序先加载并连接该类
  2. 假如该类的直接父类还没有被初始化,则先初始化其直接父类
  3. 假如类中有初始化语句,则系统依次执行这些初始化语句,哪些情况下才会执⾏?
    • 创建类的实例,也就是new的方式
    • 访问某个类或接口的静态变量,或者对该静态变量赋值
    • 调⽤类的静态方法
    • 反射(如Class.forName)
    • 初始化某个类的⼦类,则其⽗类也会被初始化
    • Java虚拟机启动时被标明为启动类的类(Java Test),直接使用java.exe命令来运行某个主类

类的销毁

在如下几种情况下,Java虚拟机将结束⽣命周期

  • 执行了System.exit()方法
  • 程序正常执行结束
  • 程序在执行过程中遇到了了异常或错误⽽而异常终⽌
  • 由于操作系统出现错误⽽导致Java虚拟机进程终止

类加载器有哪些

在这里插入图片描述
注意:这里⽗类加载器并不是通过继承关系来实现的,而是采用组合实现的。 站在Java开发⼈员的⻆度来看,类加载器器可以⼤大致划分为以下三类:

  1. 启动类加载器:Bootstrap ClassLoader,负责加载存放在JDK\jre\lib下(JDK代表JDK的安装目录,下同),或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.*开头的类均被Bootstrap ClassLoader加载)。启动类加载器是无法被Java程序直接引⽤的。
  2. 扩展类加载器器:Extension ClassLoader,该加载器器由sun.misc.Launcher$ExtClassLoader实现,它负责加载JDK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器。
  3. 应用程序类加载器:Application ClassLoader,该类加载器sun.misc.Launcher$AppClassLoader来实现,它负责加载⽤户类路径(ClassPath)所指定的类,开发者可以直接用该类加载器,如果应⽤用程序中没有自定义过⾃己的类加载器,一般情况下这个就是程序中默认的类加载器。

应用程序都是由这三种类加载器互相配合进行加载的,如果有必要,我们还可以加⼊入⾃定义的类加载器。

什么是双亲委派模型?

双亲委派模型的工作流程是:如果⼀个类加载器器收到了类加载的请求,它⾸先不会⾃己去尝试加载这个类,⽽是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当⽗类载器在它的搜索范围中没有找到所需的类时,即⽆法完成该加载,⼦加载器才会尝试自己去加载该类。

工作流程为:

  1. AppClassLoader加载⼀个class时,它⾸先不不会⾃己去尝试加载这个类,⽽是把类加载请求委派给⽗类加载器ExtClassLoader去完成。
  2. ExtClassLoader加载⼀个class时,它⾸先也不会⾃己去尝试加载这个类,⽽是把类加载请求委派给BootStrapClassLoader去完成。
  3. 如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使⽤ExtClassLoader来尝试加载;
  4. 若ExtClassLoader也加载失败,则会使⽤AppClassLoader来加载,如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException

双亲委派模型意义:

  • 系统类防止内存中出现多份同样的字节码
  • 保证Java程序安全稳定运行

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

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

相关文章

Go学习第十八章——Gin日志与第三方工具Logrus

Go web框架——Gin日志与第三方工具Logrus Gin日志功能1 基础介绍1.1 快速入门1.2 日志基础使用1.3 将日志输出到文件 2 定义路由格式3 修改日志级别4 修改日志格式 第三方日志工具logrus1 快速入门1.1 安装1.2 使用 2 基本功能使用2.1 设置日志输出格式2.2 设置日志输出位置2.…

TYWZOJ 种树苗 待定题解

文章目录 题目描述输入格式输出格式样例样例输入样例输出 数据范围与提示思路与部分实现完整代码 题目描述 在游戏 Minecraft 中&#xff0c;玩家可以通过种树来使木材再生。玩家需要将树苗种在泥土上&#xff0c;然后等待它长成大树&#xff0c;期间可以利用骨粉来催熟树苗。…

[NSSCTF 2nd] web刷题记录

文章目录 php签到MyBox非预期解预期解 php签到 源代码 <?phpfunction waf($filename){$black_list array("ph", "htaccess", "ini");$ext pathinfo($filename, PATHINFO_EXTENSION);foreach ($black_list as $value) {if (stristr($ext, …

[python 刷题] 974 Subarray Sums Divisible by K

[python 刷题] 974 Subarray Sums Divisible by K 题目如下&#xff1a; Given an integer array nums and an integer k, return the number of non-empty subarrays that have a sum divisible by k. A subarray is a contiguous part of an array. 依旧是 prefix sum 的变种…

EASYX绘制卡通头像

#include <stdio.h> #include <easyx.h> #include <iostream> #include <math.h> #define PI 3.14 // 1PI 180度 2PI 360度int main() {// 创建1024*1024的窗体initgraph(1024, 1024);// 将背景颜色设施为白色setbkcolor(WHITE);cleardevice();// to…

怀旧,20款曾经辉煌至极的PC软件,用过5个你是老网民

博主是1999年接触电脑的&#xff0c;2000年家里有了台式机&#xff0c;然后和众多孩子一样&#xff0c;迷上了这玩意&#xff0c;虽然博主也毫无意外地沉迷游戏&#xff0c;但同时也对早期的电脑硬件、软件技术有过深入研究&#xff0c;比如BIOS、注册表、黑客技术这种东西。今…

Chatgpt网页版根据关键词自动批量写原创文章软件【可多开自动登录切换gpt账号】

Chatgpt网页版根据关键词自动批量写原创文章软件介绍&#xff1a; 1、需要放入GPT账号和密码放入在账号库.txt里&#xff0c;可以放入多组账号密码&#xff0c;账号切换轮流使用。 2、可以自定义回答指令&#xff0c;也可多个回答指令随机切换。 3、可以给关键词加双标题&…

队列(Queue)概念+通过单、双链表来模拟队列+环形队列+OJ面试题(用队列实现栈、用栈实现队列、设计环形队列)

文章目录 队列(Queue)一、 概念1.尾进头出 二、模拟队列1.单链表实现队列1.1 设置结点1.2 入队offer1.3出队 poll1.4 empty方法&#xff0c;peek方法&#xff0c;getUsedSize方法 2.双链表实现队列2.1 创建结点2.2 入队列2.3 出队列2.4 peek、size、isEmpty方法 三、环形队列1.…

基于Java的婚纱摄影网站系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

基于Java的民航售票管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

C++深度优化(DFS)算法的应用:收集所有金币可获得的最大积分

涉及知识点 深度优化(DFS) 记忆化 题目 节点 0 处现有一棵由 n 个节点组成的无向树&#xff0c;节点编号从 0 到 n - 1 。给你一个长度为 n - 1 的二维 整数 数组 edges &#xff0c;其中 edges[i] [ai, bi] 表示在树上的节点 ai 和 bi 之间存在一条边。另给你一个下标从 0…

利用二叉树对表达式求值(只能处理个位的操作数)

题目&#xff1a; 题目要求: 用二叉树来表示表达式&#xff0c;树的每一个节点包括一个运算符和运算数。代数表达式中只包含&#xff0c;-&#xff0c;*&#xff0c;/&#xff0c;&#xff08;&#xff0c;&#xff09;和一位整数且没有错误。按照先括号&#xff0c;再乘除&am…

批量爬取指定多个网址的爱站权重关键词词库(爱站拓词自动去重)

批量爬取指定多个网址的爱站权重关键词词库软件介绍&#xff1a; 1、软件可以设置权重词的长度范围。 2、可设置权重词必须包含词。 3、可以设置爬取的页数。 4、可以设置爬取PC权重词、移动权重词。 5、可以放入多个网站&#xff0c;批量爬取多个网站的权重词。 6、爬取完…

Ubuntu更新中文包

设置 重启Ubuntu系统

灯光布置和场景模拟软件:Set A Light 3D Studio

Set A Light 3D Studio是一款专业的灯光模拟软件&#xff0c;旨在帮助摄影师和电影制片人在电脑上进行虚拟灯光布置和场景模拟&#xff0c;以实现更加精准和高质量的拍摄效果。该软件提供了丰富的灯光和场景模型&#xff0c;支持灵活调整光源位置、强度、颜色和效果等参数&…

IOC课程整理-20 Spring 应用上下文生命周期

0.目录 1. Spring 应用上下文启动准备阶段 2. BeanFactory 创建阶段 3. BeanFactory 准备阶段 4. BeanFactory 后置处理阶段 5. BeanFactory 注册 BeanPostProcessor 阶段 6. 初始化內建 Bean&#xff1a;MessageSource 7. 初始化內建 Bean&#xff1a;Spring 事件广播器…

Megatron-LM GPT 源码分析(四) Virtual Pipeline Parallel分析

引言 本文接着上一篇【Megatron-LM GPT 源码分析&#xff08;三&#xff09; Pipeline Parallel分析】&#xff0c;基于开源代码 GitHub - NVIDIA/Megatron-LM: Ongoing research training transformer models at scale &#xff0c;通过GPT的模型运行示例&#xff0c;从三个维…

sql-50练习题6-10

sql练习题6-10题 前言数据库表结构介绍学生表课程表成绩表教师表 0-6 查询"李"姓老师的数量0-7 查询学过"李四"老师授课的同学的信息0-8 查询没学过"李四"老师授课的同学的信息0-9 查询学过编号为"01"并且也学过编号为"02"的…

37回溯算法-理论基础

目录 什么是回溯算法 基本思想 问题场景 回溯算法的理解 回溯算法模板 LeetCode之路——257. 二叉树的所有路径 分析 什么是回溯算法 回溯算法是一种解决组合优化问题、搜索问题以及决策问题的算法。它通常用于尝试在一组可能的解决方案中搜索并找到满足特定条件的解。…

C++入门05—指针

1. 指针的基本概念 指针的作用&#xff1a; 可以通过指针间接访问内存 内存编号是从0开始记录的&#xff0c;一般用十六进制数字表示 可以利用指针变量保存地址 2. 指针变量的定义和使用 指针变量定义语法&#xff1a; 数据类型 * 变量名&#xff1b; 示例&#xff1a; …