【注解和反射】类加载器

继上一篇博客【注解和反射】什么时候类会和不会被初始化?-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类。

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

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

相关文章

【C++】STL-vector模拟实现

目录 1、vactor的模拟实现 1.1 成员变量 1.2 size、capacity 1.3 迭代器 1.4 构造、析构、拷贝构造、operator 1.5 push_back、pop_back、reserve 1.6 operator[] 1.7 insert、erase 1.8 resize 2、使用memcpy拷贝问题 1、vactor的模拟实现 1.1 成员变量 vector是顺…

时尚新选择,小塔RFID技术重塑样衣管理

在时尚领域,样衣是创意与工艺的完美结合,每一件都承载着设计师的心血与期待。然而,当这些珍贵的样版在传统的管理体系下流转时,样版管理成为一个令人头疼的问题。手动记录、盘点和样板追溯成为常态,但这种方式容易出错…

机器学习(二)之监督学习

前言: 上一节大概讲解了几种学习方式,下面几张就具体来讲讲监督学习的几种算法。 以下示例中和都是权重的意思!!! 注:本文如有错误之处,还请读者指出,欢迎评论区探讨! 1…

17. map和set的模拟实现(也就是用红黑树封装map和set)

1.map和set底层调用的红黑树的实现 有不清楚的地方&#xff0c;参考AVL树的模拟实现和红黑树的模拟实现 红黑树迭代器的实现 // 红黑树迭代器的类模板 template<class T, class Ref, class Ptr> struct __RBTreeIterator {// 将红黑树节点的类类型定义为Nodetypedef R…

绽放新笑容:儿童换牙期的关怀与注意

引言&#xff1a; 儿童的换牙期是成长过程中的重要阶段&#xff0c;标志着他们逐渐迈向成人世界。然而&#xff0c;伴随着牙齿的脱落和新牙的生长&#xff0c;孩子们可能会经历一些不适和困扰。本文将探讨儿童换牙期的注意事项&#xff0c;以帮助家长和孩子们度过这一特殊时期&…

扎根理论分析原理、方法与Nvivo技术应用

扎根理论越来越流行&#xff0c;成为经常被采用的研究方法之一。扎根理论的研究者来自广泛的研究领域&#xff0c;例如社会工作、护理、医药、综合医疗保健、教育、管理和商业。这些从业者和学者试图从他们所在学科范围内解释行为模式。对于扎根理论本质和实践的研究引发了知名…

这个表格为什么在VS Code里面预览可以显示,在浏览器预览就没有显示

在VS Code里面预览可以显示如图&#xff1a; 在浏览器预览就不能显示了&#xff0c;刚开始还好的后来不知道弄错了哪里了&#xff0c;哭死 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"vi…

Swagger:在线接口文档

Swagger介绍及使用 官网:https://swagger.io/ 介绍 使用Swagger你只需要按照它的规范去定义接口及接口相关的信息&#xff0c;就可以做到生成接口文档&#xff0c;以及在线接口调试页面。 Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。 使用方式 1.导入 kni…

qt5-入门-QListWidget-通过右键快捷菜单复制item内容

参考&#xff1a; C GUI Programming with Qt 4, Second Edition 本地环境&#xff1a; win10专业版&#xff0c;64位&#xff0c;Qt5.12 效果 在某个item上右键&#xff0c;点击copy后&#xff0c;item的内容已复制到剪贴板。 实现 #include <QMenu> #include <…

如何用微信发布考试成绩(如月考、期中、期末等)

自教育部《未成年人学校保护规定》颁布后,教育部明确表示:学校不得公开学生的考试成绩、排名等信息!同时学校应采取措施,便利家长知道学生的成绩等学业信息,对于教师来说,如何用微信发布考试成绩(如:月考、期中、期末等)就成了一道难题... 公开吧,会伤害到学生自尊心,甚至被投诉…

创建钉钉审批流实例

1、依赖 <!--钉钉 api --> <dependency><groupId>com.aliyun</groupId><artifactId>dingtalk</artifactId><version>2.0.14</version> </dependency> <!--钉钉 事件订阅--> <dependency><groupId>co…

CUDA编程技术概述

CUDA&#xff08;Compute Unified Device Architecture&#xff0c;统一计算设备架构&#xff09;是由英伟达&#xff08;NVIDIA&#xff09;公司推出的一种软硬件集成技术&#xff0c;是该公司对于GPGPU&#xff08;通用图形处理器计算&#xff09;的正式名称。透过这个技术&a…

Levenberg-Marquardt (LM) 算法进行非线性拟合

目录 1. LM算法2. 调包实现3. LM算法实现4. 源码地址 1. LM算法 LM算法是一种非线性最小二乘优化算法&#xff0c;用于求解非线性最小化问题。LM主要用于解决具有误差函数的非线性最小二乘问题&#xff0c;其中误差函数是参数的非线性函数&#xff0c;需要通过调整参数使误差函…

eNSP学习——静态路由及默认路由基本配置

目录 知识背景 实验目的 实验步骤 实验内容 实验拓扑 实验编址 实验前期准备 实验步骤 1、基本配置&#xff08;按照实验编址设置好对应的IP地址&#xff09; 2、是实现主机之间的通信 3、实现全网全通来增强网络的可靠性 4、使用默认路由实现简单的网络优化 需要各…

HTB靶场 Perfection

端口 打开了ssh和http服务 访问 Perfection靶机的网站 是一个根据权重计算总成绩的网站 Wappalyzer查看网页用的什么编写搭建的 抓包看一下是怎么工作的 发送,&#xff0c;返回的结果 如果我在 类别 后面多加一句命令 就会出现提示 恶意输入阻止 大概率有命令注入 通过插件…

解决宏定义后面无法加分号

总结&#xff1a;注意是针对单行if语句使用&#xff0c;并且宏定义后面必须带分号&#xff08;格式统一&#xff09; 参考连接 C语言种do_while(0)的妙用_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1vk4y1R7VJ/?spm_id_from333.337.search-card.all.click&vd_…

2万8金句美句格言签名句子ACCESS\EXCEL数据库

优美句子类的数据已经有《33万多优美句子经典句子ACCESS数据库》、《近2万签名的句子网络签名ACCESS数据库》、《24万QQ伤感签名微信签名ACCESS数据库》、《2万多条QQ签名论坛签名大全ACCESS数据库》&#xff0c;今天又遇到一个&#xff0c;感觉也很不错&#xff0c;发上来看看…

pip安装的python包放在哪里了?—— ubuntu系统

1 pip 安装了哪些包 2 包安装在哪里了 thirty-twott:~/Desktop$ pip show openai Name: openai Version: 1.19.0 Summary: The official Python library for the openai API Home-page: Author: Author-email: OpenAI <supportopenai.com> License: Location: /ho…

Cairo

文章目录 关于 Cairo 关于 Cairo 官网&#xff1a;https://cairographics.org官方文档&#xff1a;https://cairographics.org/documentation/ Cairo是一个支持多个输出设备的2D图形库。 当前支持的输出目标 包括 X Window System&#xff08;通过Xlib 和 XCB&#xff09;、Qu…

Gartner发布攻击面管理创新洞察:CTEM、VA、EASM、CAASM、ASA、DRPS、BAS、VM等攻击面管理相关技术及关系

安全运营团队负责管理跨内部和外部数字资产的复杂攻击面。这项研究概述了攻击面评估空间&#xff0c;以帮助安全和风险管理领导者驾驭技术并改善其安全状况。 主要发现 随着本地和云中的技术环境变得越来越复杂和分散&#xff0c;组织必须管理不断增长的攻击面。 SaaS 应用程序…