类加载是Java如此流行的一个重要因素,是一个Java程序的起点,是万物的起源。

Java类加载的简单介绍

Java中的类加载大体分为四类:启动类加载器(Bootstrap ClassLoader)扩展类加载器(Extension ClassLoader)应用程序类加载器(Application ClassLoader)用户自定义类加载器(User ClassLoader)

启动类加载器:

负责加载JDK目录中\lib文件夹中的类,或者被-Xbootclasspath参数指定的路径下的可识别类。整个Java系统中很多基本组件都是有启动类加载器加载的,就连扩展类加载器和应用程序类加载器都是通过它加载的。在一个Java程序运行时,首先启动JVM,之后马上就诞生了启动类加载器,然后启动类加载器加载剩下两个系统加载器,之后这两个加载器再加载他们应该加载的类。

扩展类加载器:

负责加载JDK目录中\lib\ext文件夹中的类,或者被java.ext.dirs系统变量所指定的路径中的类库。这个类加载器的作用是用来与启动类加载器合作加载系统组件的。

应用程序类加载器:

负责加载ClassPath路径下的类,可以通过getSystemClassLoader()获取。如果没有自己定义类加载,我们编写的Java类都将被这个类加载器加载。是程序中的默认类加载。

用户自定义类加载器:

用户自己编写的类加载器,可以通过覆盖findClass()方法去进行加载类。

Java类与类加载的关系

Java的类与类加载是息息相关的,只有一个Java类全限定名并不能确定唯一的Java类。Java类只有与类加载一起才能确定一个唯一的类对象。

比如有一个com.test.T1类,然后我们在程序中自定义两个类加载,通过两个类加载器加载的两个com.test.T1类是不同的。一个程序中会有两个T1类对象。

当类加载器加载类时,会在类加载的名称空间中标识该类名称,以保证类加载器和类全名共同确定一个类对象。

双亲委派机制

如上图箭头所示,除了启动类加载器,每个类加载器都有一个父加载器。构成了一个类加载器结构系统。这个系统就是用来完成双亲委派机制的。

观察loadClass源码可以明白,一个类加载器加载一个类时,首先会把加载动作委派给他的父加载器,如果父加载器无法完成这个加载动作时才由该类加载器进行加载。由于类加载器会向上传递加载请求,所以一个类加载时,首先尝试加载它的肯定是启动类加载器(逐级向上传递请求,直到启动类加载器,它没有父加载器),之后根据是否能加载的结果逐级让子类加载器尝试加载,直到加载成功。

比如我们自己写了一个com.test.T1类,假设我们没有自定义类加载器,那么这个类会由应用程序类加载器加载。应用程序类加载器加载时先把加载任务委派给扩展类加载器(父加载器),然后扩展类加载器再把加载任务委托给启动类加载器(父加载器),启动类加载器没有父加载器。于是它自己尝试加载,结果发现T1类并不在自己的记载类路径之中,于是告诉扩展类加载器(子加载器)自己无法加载该类。这时扩展类只好自己加载这个类,结果发现也无法加载该类,于是它也告诉应用程序类加载器这个消息,这时应用程序类加载器自己进行T1类的加载动作,加载成功。

可以把每个类加载都想成一个大懒汉,每次让他办事时他都让爸爸代办。没想到爸爸也是个大懒汉,于是爸爸也让他的爸爸代办。这是到了爷爷那里,爷爷也很懒,但是他没有爸爸了,于是只能一边抱怨一边干,然后发现自己做不了,又骂骂咧咧的把活儿交给了自己的儿子,然后爸爸开始干活,发现自己也不能完成这个任务,于是他也是骂骂咧咧的把活交给了儿子,儿子挨了一顿骂,然后开始干活,经过了1小时的苦干,这个活儿终于完事了。

双亲委派机制的存在意义

双亲委派是Java语言的一大创新。表明看起来,由于双亲委派机制的存在,类加载器的数量增多了不少,增加了程序的复杂性。不过存在既有道理。双亲委派机制让Java类体系变得稳定,有层次性能。特定的类由特定的类加载器加载,每次加载都委托父类的过程让类对象在内存中的数量保持为一个,让同类名的类无法被替换。

如果没有双亲委派机制,只有一个类加载器,我们自己写一个java.lang.Object类,也可以被加载,结果就是内存中有两个Object类,引用的时候会造成安全的问题。而且一些核心的类可能会被替换,导致重大的安全问题。

有了双亲委派机制,我们自己写的java.lang.Object类在加载时会被加载器委托给父加载器,在某一个父加载器中发现内存中已经存在了java.lang.Object类,那么将不会进行加载,这样就保证了特定的类只能有一个在内存中。

不要破坏双亲委派机制

双亲委派机制不是强制性的,所以我们不经意的编码可能会对它造成破坏。如何让我们自己编写的类加载器安全的融入双亲委派机制呢?

public abstract class ClassLoader {...public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {//判断该类是否存在Class<?> c = findLoadedClass(name);if (c == null) {...try {//如果存在父加载器就委托给父加载器if (parent != null) {c = parent.loadClass(name, false);} else {//如果不存在父加载器就委托给启动类加载器c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {//捕捉父类发出的 无法加载该类 的异常}if (c == null) {...//父类无法加载类,有该类加载器本身进行加载c = findClass(name);// do some stats...}}if (resolve) {resolveClass(c);}return c;}}protected Class<?> findClass(String name) throws ClassNotFoundException {throw new ClassNotFoundException(name);}...
}

loadClass()方法是一个类加载的主要方法,从代码中我们可以看出该类加载器进行类加载的操作集中在findClass()方法中,loadClass()方法其余的代码都是在维护双亲委派机制,所以我们在实现自己的类加载器时只需重新findClass()方法即可,让loadClass()方法保持原样以便双亲委派机制的正确运行。

2020-09-30相关推荐

  1. 2020.09.30【RNA-seq流程】丨转录组生信分析全流程

    RNA-Seq生信分析全流程 摘要 第一部分 step.1 下载数据 step.2 数据质控 第二部分 step.3序列比对 step.4 计算基因表达量 step.5 插入片段长度检验 step.6 ...

  2. 2020. 09 青少年机器人技术等级考试理论综合试卷(一级)

    2020. 09 青少年机器人技术等级考试理论综合试卷(一级) 一. 单选题(共 30 题, 共 60 分) 1.使用下列工具不能省力的是? ( ) A.斜面 B.动滑轮 C.定滑轮 D.省力杠杆 试 ...

  3. RDKit | 基于RDKit(≥2020.09.1)的相似图绘制新方法

    导入库 from rdkit import Chem from rdkit.Chem import Draw from rdkit.Chem.Draw import SimilarityMaps fr ...

  4. 实验室每日一题 2020.11.30

    实验室每日一题 2020.11.30 先打开没有加密的文本文档,里面有一串密文,根据结尾的+推测应该是XXencode,直接找个在线网站解密,又得到一串密文:fwilvyhublqwhuhvwlqj, ...

  5. 多益网络校招前端面经(2020.09.24)

    多益网络校招前端面经(2020.09.24) 面试平台 QQ视频通话 时长 大约半小时 过程 自我介绍 项目问题:项目中遇到的问题以及解决方式:在团队开发过程中个成员合作方式,遇到问题的解决方式 cs ...

  6. 2022 CCF 非专业级别软件能力认证第一轮 (CSP-J1)入门级 C++语言试题 认证时间:2022 年 9 月 18 日 09:30~11:30

    今天的考试题,有点乱 2022 CCF 非专业级别软件能力认证第一轮 (CSP-J1)入门级 C++语言试题 认证时间:2022 年 9 月 18 日 09:30~11:30 考生注意事项:  试题 ...

  7. 【2019.09.30】“福大同好”——原型设计展示~(软工实践第四次作业)

    [2019.09.29]更新:在页面的右侧新增了导航栏,方便阅读.评论区更新了背景图. [2019.09.30]更新:<构建之法>四五八章读后感:https://www.cnblogs.c ...

  8. 英语积累知识(二) 2020/1/30 2019年12月六级翻译

    英语积累知识(二) 2020/1/30 2019年12月六级翻译 简言:笔者在2019年12月份参加的CET6 的翻译题是"梅花",在这里特将三份试卷的翻译及重点词汇做详解,发现三 ...

  9. 《nature》2020.11.30期,重症COVID-19的主要遗传危险因素来自尼安德特人

    <nature>最新2020.11.30期快报! 1.重症COVID-19的主要遗传危险因素来自尼安德特人 严重COVID-19的风险是由一个遗传自尼安德特人的基因组片段引起的,南亚和欧洲 ...

  10. 2020/7/30 渐入佳境

    2020/07/30 第二次组队赛(模拟) 比赛过程 开始 意外 解决 进入状态 学到的题目 B题 C题 L题 赛后总结反思 比赛过程 开始 集训第4天,中午12:00开始组队赛.开始的时候不知道先做 ...

最新文章

  1. Transformer大升级!谷歌、OpenAI联合推出分层模型,刷榜ImageNet32刷新SOTA
  2. C#: .net序列化及反序列化 [XmlElement(“节点名称”)] [XmlAttribute(“节点属性”)] (上篇)...
  3. 框架之---Django
  4. 吴恩达深度学习课程deeplearning.ai课程作业:Class 4 Week 4 Art Generation with Neural Style Transfer
  5. 库存管理系统软件测试,药房库存管理系统模块测试用例
  6. 2019.7.13刷题统计
  7. SQL Server灾难恢复方法
  8. 设计模式之观察者模式demo
  9. java获取文件名方法,利用Java获取文件名、类名、方法名和行号的方法小结
  10. 腾讯QQ团队开源分布式后台毫秒服务引擎全解析:引擎架构、RPC、灰度……
  11. [转载] Numpy数组对象ndarray
  12. 软件测试用例详细规范
  13. 在推送Git之前合并多个提交[重复]
  14. 10大习惯让你变年轻
  15. 亚马逊SP-API对接-网站授权
  16. pipe()函数详解
  17. c#调用触滑输入法实现触摸屏键盘功能
  18. SAS 学习笔记(六)— SAS与属性数据分析
  19. 运维人员必备的Linux系统命令汇总
  20. Java调用MySQL并返回数据_Java调用MySQL存储过程并获得返回值的方法

热门文章

  1. UVA - 1588 Kickdown
  2. J2EE基础篇——十三个规范
  3. .net中Windows窗体间的数据交互
  4. instanceof constructor Object.prototype.tostring.call ( [] )区别 数组和 对象的3中方法
  5. 在vue的项目中引入swiper插件
  6. 阿里云负载均衡SSL证书配置(更新)
  7. 计算机二级C语言冲刺笔记。
  8. 2015年7月15日 JS第一课(JS,声明变量,数据类型)
  9. .net System.IO之Stream的使用详解
  10. asp.net gridview添加删除确认对话框