【注解和反射】类加载器

news2024/11/16 12:00:35

继上一篇博客【注解和反射】什么时候类会和不会被初始化?-CSDN博客

目录

六、类加载器

测试:获得类加载器

(1)如何获取Java中的类加载器及其父类加载器

(2)测试当前类是哪个类加载器

(3)获取系统类加载器可以加载的路径

双亲委派机制

自己如果写一个自己的String类,路径是java.lang.String,可以吗?


六、类加载器

类加载器(ClassLoader)是Java运行时环境(JRE)的一部分,它负责在运行时动态地加载Java类到Java虚拟机(JVM)中。类加载器本身也是一个类,其实质是把类文件从硬盘读取到内存中。

类加载器的主要作用包括:

  1. 加载类:根据类的全名(包括包名)找到对应的.class文件,并将其加载到JVM中。加载的方式分为隐式加载和显示加载两种。隐式加载指的是程序在使用new等方式创建对象时,会隐式地调用类的加载器把对应的类加载到JVM中。
  2. 链接:这个过程包括验证、准备和解析三个步骤。验证是确保被加载的类的正确性和安全性;准备是为类的静态变量分配内存,并将其初始化为默认值;解析是把类中的符号引用转换为直接引用。
  3. 初始化:为类的静态变量赋予正确的初始值。

此外,Java中有三种主要的类加载器,它们分别是:

  1. 启动类加载器(Bootstrap ClassLoader):这是JVM自带的类加载器,负责加载Java的核心类库,如rt.jar等。
  2. 扩展类加载器(Extension ClassLoader):负责加载Java的扩展类库,它的父加载器是Bootstrap。
  3. 系统类加载器(System ClassLoader):也称为应用类加载器(Application ClassLoader),负责加载应用程序classpath目录下的所有类。它的父加载器是Extension ClassLoader。

类加载器采用双亲委派模型进行类的加载,这种模型确保了Java核心API的稳定性和防止了一些安全问题。

测试:获得类加载器

这段Java代码定义了一个名为Test04的公共类,其中包含了main方法作为程序的入口点。

(1)如何获取Java中的类加载器及其父类加载器

该程序主要展示了如何获取并打印Java中的类加载器及其父类加载器。

public class Test04 {
  public static void main(String[] args) {
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    System.out.println(systemClassLoader);

    ClassLoader parent = systemClassLoader.getParent();
    System.out.println(parent);

    ClassLoader parent1 = parent.getParent();
    System.out.println(parent1);
  }
}

具体来说,代码做了以下几件事情:

  1. 通过调用ClassLoader.getSystemClassLoader()方法获取了系统类加载器(System ClassLoader),它通常用于加载应用程序classpath下的类。
  2. 打印了系统类加载器的信息。这通常会输出类加载器的类名和一些详细信息,比如类加载器的哈希码等。
  3. 调用系统类加载器的getParent()方法获取其父类加载器,即扩展类加载器(Extension ClassLoader)。这个类加载器用于加载Java的扩展类库。
  4. 打印了扩展类加载器的信息。
  5. 再次调用父类加载器的getParent()方法,理论上应该获取到启动类加载器(Bootstrap ClassLoader)。但是,启动类加载器在Java中是用C++实现的,因此在Java代码中并不能直接获取到它的实例。因此,这段代码会打印出null

(2)测试当前类是哪个类加载器

public class Test04 {
  public static void main(String[] args) throws ClassNotFoundException {
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    System.out.println(systemClassLoader);

    ClassLoader parent = systemClassLoader.getParent();
    System.out.println(parent);

    ClassLoader parent1 = parent.getParent();
    System.out.println(parent1);

    ClassLoader classLoader = Class.forName("com.itheima.sjms.Test04").getClassLoader();
    System.out.println(classLoader);

    ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
    System.out.println(classLoader1);
  }
}

在这段扩展后的Java代码中,除了原有的类加载器层次结构打印之外,还添加了两行用于通过Class.forName()方法获取特定类的类加载器,并打印它们的信息。

  1. 使用Class.forName("com.itheima.sjms.Test04").getClassLoader():获取Test04类的类加载器并打印。

    1. 这将返回加载Test04类的类加载器,如果Test04类位于应用程序的classpath下,那么这通常是系统类加载器。

  2. 使用Class.forName("java.lang.Object").getClassLoader():获取java.lang.Object类的类加载器并打印。

    1. 这将返回加载java.lang.Object类的类加载器。由于Object类是Java核心类库的一部分,它通常是由引导类加载器加载的。但是,在这里打印出的结果可能会是null,因为如前所述,引导类加载器在Java中是不可见的,无法直接获取。

(3)获取系统类加载器可以加载的路径

在Java中,System.getProperty("java.class.path") 是用来检索Java类路径(classpath)的系统属性。类路径是JVM和Java工具用来查找用户定义的类和第三方库的一组目录和文件。

public class Test04 {
  public static void main(String[] args) throws ClassNotFoundException {
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    System.out.println(systemClassLoader);

    ClassLoader parent = systemClassLoader.getParent();
    System.out.println(parent);

    ClassLoader parent1 = parent.getParent();
    System.out.println(parent1);

    ClassLoader classLoader = Class.forName("com.itheima.sjms.Test04").getClassLoader();
    System.out.println(classLoader);

    ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
    System.out.println(classLoader1);

    System.out.println(System.getProperty("java.class.path"));
  }
}

这行代码会打印出当前Java进程的类路径设置。类路径通常包含:

  • 当前目录(.
  • JAR文件的路径(以分号;分隔,在Windows系统中;在Unix/Linux系统中使用冒号:分隔)
  • 包含.class文件的目录
  • 以及其他可能包含类或资源的目录和文件
D:\my\else\code-learning\java-study\code\out\production\exercises;
D:\my\else\code-learning\java-study\code\exercises\lib\gson-2.6.2.jar;
D:\my\else\code-learning\java-study\code\tankwar2.zip;
D:\my\else\code-learning\java-study\code\1_bsm-30min.jar;C:\Users\xxx\.m2\repository\org\junit\jupiter\junit-jupiter\5.8.1\junit-jupiter-5.8.1.jar;
C:\Users\xxx\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.8.1\junit-jupiter-api-5.8.1.jar;
C:\Users\xxx\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;
C:\Users\xxx\.m2\repository\org\junit\platform\junit-platform-commons\1.8.1\junit-platform-commons-1.8.1.jar;
C:\Users\xxx\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;
C:\Users\xxx\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.8.1\junit-jupiter-params-5.8.1.jar;
C:\Users\xxx\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.8.1\junit-jupiter-engine-5.8.1.jar;
C:\Users\xxx\.m2\repository\org\junit\platform\junit-platform-engine\1.8.1\junit-platform-engine-1.8.1.jar

类路径是在启动Java应用程序时通过-cp-classpath命令行选项设置的,或者由环境变量CLASSPATH指定(尽管环境变量方法不太推荐,因为它可能对系统中的所有Java应用程序产生全局影响)。

类路径对于Java应用程序至关重要,因为JVM需要知道在哪里可以找到所有的类和资源文件,以便能够正确地加载和运行程序。如果类路径设置不正确,JVM可能会抛出ClassNotFoundException或其他相关异常,因为它找不到必要的类文件。

双亲委派机制

双亲委派机制是Java中的一种类加载机制。当一个类加载器收到类加载请求时,它不会自己首先去加载这个类,而是将这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中。只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

这种机制的设计主要是为了确保Java核心API的稳定性和防止代码被一些恶意的代码所篡改。例如,如果没有使用双亲委派模型,而是由各个类加载器自行去加载的话,如果用户自己编写了一个称为java.lang.Object的类,并放在程序的ClassPath中,那系统中将会出现多个不同的Object类,Java类型体系中最基础的行为也就无法保证,应用程序也将会变得一片混乱。

自己如果写一个自己的String类,路径是java.lang.String,可以吗?

在Java中,自己写一个类并将其放在java.lang包下,尤其是命名为String,是不被推荐的,实际上也是不允许的,原因主要有以下几点:

  1. 包名保护java.lang是Java核心API的包名,它是保留给Java平台使用的。试图在自己的代码中使用这个包名可能会导致编译时错误或警告,甚至在某些环境中可能根本无法编译。

  2. 类加载器的双亲委派机制:即使你能够编译一个类并将其放入java.lang包,Java的类加载器也不会加载它。

    1. 双亲委派机制确保核心类库中的类总是被优先加载,而且是由最顶层的类加载器(即引导类加载器)加载的。自定义的java.lang.String类不会由系统类加载器或引导类加载器加载,因为引导类加载器已经加载了Java平台提供的String类。

  3. 安全性:Java的安全模型不允许覆盖或修改核心类库中的类,以防止恶意代码破坏Java运行环境的安全性和稳定性。

  4. 二进制兼容性:Java的核心类库是为所有Java程序提供的通用接口,它们的二进制兼容性非常重要。允许自定义这些类可能会引入不一致性,从而破坏不同Java应用程序之间的互操作性。

  5. 类和方法的final修饰符:在java.lang包中的很多类和方法都被声明为final,包括String类。final类不能被继承,这意味着你不能创建一个新的String子类,更不用说替换原始的String类了。

  6. 已有的String:Java中已经有了一个功能完善、经过严格测试和优化过的String类。在大多数情况下,你不需要(也不应该)重新实现这个功能。如果你需要不同的字符串处理功能,可以通过扩展现有的类或使用组合来实现,而不是尝试从头开始创建一个新的String类。

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

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

相关文章

深度学习-线性代数

目录 标量向量矩阵特殊矩阵特征向量和特征值 标量由只有一个元素的张量表示将向量视为标量值组成的列表通过张量的索引来访问任一元素访问张量的长度只有一个轴的张量,形状只有一个元素通过指定两个分量m和n来创建一个形状为mn的矩阵矩阵的转置对称矩阵的转置逻辑运…

hbase 集成 phoenix 实现 sql 化

1. 依赖 hbase > hbase 集群搭建 2. 下载安装包 点击下载 ps:该网页在内网可能打不开,遇到该情况有条件的可以打开 VPN 在下载 3. 上传解压 使用工具将安装包上传的服务器上 笔者这里选择 上传到 /opt/software 目录,解压到 /opt/mo…

[Algorithm][前缀和][和为K的子数组][和可被K整除的子数组][连续数组][矩阵区域和]详细讲解

目录 1.和为 K 的子数组1.题目链接2.算法原理详解3.代码实现 2.和可被 K 整除的子数组1.题目链接2.算法原理详解3.代码实现 3.连续数组1.题目链接2.算法原理详解3.代码实现 4.矩阵区域和1.题目链接2.算法原理详解3.代码实现 1.和为 K 的子数组 1.题目链接 和为 K 的子数组 2.…

目标检测——YOLOv7算法解读

论文:YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors (2022.7.6) 作者:Chien-Yao Wang, Alexey Bochkovskiy, Hong-Yuan Mark Liao 链接:https://arxiv.org/abs/2207.02696 代码:h…

十大排序算法详解-上篇:比较排序算法【python 动态图解】

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。 会一些的技术:数据分析、算法、SQL、大数据相关、python 欢迎加入社区:码上找工作 作者专栏每日更新: LeetCode解锁1000题: 打怪升级之旅 python数据分析…

如何通过cURL库实现远程控制插座

如何通过cURL库实现远程控制插座呢? 本文描述了使用cURL库调用HTTP接口,实现控制插座,即插即用,先插入插座,再接电器,实现远程控制。 可选用产品:可根据实际场景需求,选择对应的规格…

libtorrent - 安装小记

文章目录 官方文档:libtorrent python binding http://libtorrent.org/python_binding.html 1、下载代码 建议使用: git clone --recurse-submodules https://github.com/arvidn/libtorrent.git如果在 github web 界面下载代码,build 的时候…

进程动静态库

文章目录 动态库和静态库1. 静态库2. 动态库 承接上文: 文件描述符 动态库和静态库 静态库与动态库: 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库动态库&#xf…

ISP比普通的静态代理相比有什么优势?

ISP(Internet Service Provider),即互联网服务提供商,是向广大用户综合提供互联网接入业务、信息业务、增值业务的电信运营商。而静态代理则是一个固定不变的代理IP地址,具有稳定性强、兼容性好和管理方便等特点。当我…

上位机图像处理和嵌入式模块部署(树莓派4b之自动化测试)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 硬件、软件功能开发ok只是产品开发的第一步。怎么做到自动化测试、保证产品质量才是关键。很多时候,我们给客户提供了功能,…

适用于集成温度补偿晶体振荡器SG3225EEN

在现代电子系统中,随着技术的发展,对晶体振荡器的要求越来越高。例如,人工智能、5G等技术的应用需要更高的频率稳定度和更低的相位噪声,以确保数据传输的准确性和系统的高效运行。此外,随着电子设备向智能化、小型化发…

PHP+MYSQL多条件选一通用搜索系统功能单文件7KB

通用功能: 快速填写参数用于自己的mysql数据表搜索,ajax载入数据 <?php header("content-Type: text/html; charsetUTF-8"); //error_reporting(0);$dbhost "localhost"; //数据库地址本地localhost $dbuser "chalidecom"; //数据库账号 …

C语言扫雷游戏完整实现(下)

文章目录 前言一、排雷函数菜单二、排雷函数菜单的实现三、拓展棋盘功能四、源码1. test.c源文件2. game.h头文件3. game.c源文件 总结 前言 C语言实现扫雷游戏的排雷菜单&#xff0c;以及功能的实现&#xff0c;拓展棋盘功能&#xff0c;以及源码等。 上半部分的链接地址: C语…

第一篇【传奇开心果系列】Python深度学习库技术点案例示例:深度解读深度学习在自动驾驶领域的应用

传奇开心果博文系列 系列博文目录Python深度学习库技术点案例示例系列 博文目录前言一、深度学习在自动驾驶方面的应用介绍二、目标检测和识别示例代码三、路况感知示例代码四、行为预测示例代码五、路径规划示例代码六、自动驾驶控制示例代码七、感知融合示例代码八、高精度地…

PyCharm开发工具安装plugins插件

一. 简介 通过前面的学习&#xff0c;我们知道 python开发常用的一个开发工具&#xff08;即IDE&#xff09;是 PyCharm。 本文来简单介绍一下&#xff0c;PyCharm开发工具是如何安装 plugins插件的。其实与 vscode软件安装插件类似。 本文来学习 PyCharm开发工具安装一个中…

51.HarmonyOS鸿蒙系统 App(ArkUI)通知

普通文本通知测试 长文本通知测试 多行文本通知测试 图片通知测试 进度条通知测试 通知简介 应用可以通过通知接口发送通知消息&#xff0c;终端用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用。 通知常见的使用场景&#xff1a; 显示接收到的短消息、…

正则表达式.java

正则表达式的作用&#xff1a; ①可以校验字符串是否满足一定的规则&#xff0c;并用来校验数据格式的合法性&#x1f9f8; &#x1f9e9;[]:只能是括号里的字符 &#x1f9e9;[^]&#xff1a;除了括号里的字符 &#x1f9e9;[- -]:表示两段范围&#xff0c;满足其一即可 &a…

openstack-镜像封装 7

再克隆两台主机并且安装图形化组件和虚拟化组件 进入图形化界面并安装一个虚拟化管理器 根下创建一个目录&#xff0c;虚拟化管理器新添加一个路径 创建虚拟化 配置虚拟化主机 设置虚拟化主机配置 安装所需软件 清理创建云主机时安装的组件 主机安装虚拟化工具 清理虚拟化缓存 …

应用在防蓝光显示器中的LED防蓝光灯珠

相比抗蓝光眼镜、防蓝光覆膜、软体降低蓝光强度这些“软”净蓝手段&#xff0c;通过对LED的发光磷粉进行LED背光进行技术革新&#xff0c;可实现硬件“净蓝”。其能够将90%以上的有害蓝光转换为450nm以上的长波低能光线&#xff0c;从硬件的角度解决了蓝光危害眼睛的问题&#…

深入探究音视频开源库WebRTC中NetEQ音频抗网络延时与抗丢包的实现机制

目录 1、引言 2、WebRTC简介 3、什么是NetEQ&#xff1f; 4、NetEQ技术详解 4.1、NetEQ概述 4.2、抖动消除技术 4.3、丢包补偿技术 4.4、NetEQ概要设计 4.5、NetEQ的命令机制 4.6、NetEQ的播放机制 4.7、MCU的控制机制 4.8、DSP的算法处理 4.9、DSP算法的模拟测试…