前言

之前详细介绍了Java类的整个加载过程(类加载机制详解)。虽然,篇幅较长,但是也不要被内容吓到了,其实每个阶段都可以用一句话来概括。

1)加载:查找并加载类的二进制字节流数据。

2)验证:保证被加载的类的正确性。

3)准备:为类的静态变量分配内存,并设置默认初始值。

4)解析:把类中的符号引用转换为直接引用。

5)初始化:为类的静态变量赋予正确的初始值。

当然,要想掌握类加载机制,还是需要去深入研究的。(好吧,说了一句正确的废话)因为其中,有很多知识点也是面试中常问的。比如,我之前去面试的时候,面试官就问到了一个和类初始化相关的问题。就是给一段代码,有父子类关系,父子类中包含静态代码块、构造代码块、普通代码块、构造函数等,然后让判断代码最终的执行顺序。(可自行思考一下,具体内容细节暂时不做扩展)

类加载器

终于来到了本文的主题 —— 类加载器和双亲委派机制。

在《深入理解Java虚拟机》中,对于类加载器的定义是这样的:

虚拟机设计团队把类加载阶段中的“通过一个类的权限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为“类加载器”。

简单来说,类加载器的作用就是去加载class类的二进制字节流的。

类加载器有以下三种:

1)启动类加载器(Bootstrap ClassLoader),或者叫根加载器。这个类加载器主要是去加载你在本机配置的环境变量 Java_Home/jre/lib 目录下的核心API,如rt.jar

2)扩展类加载器(Extension ClassLoader)。这个加载器负责加载 Java_Home/jre/lib/ext 目录下的所有jar包。

3)应用程序类加载器(Application ClassLoader)。这个加载器加载的是你的项目工程的ClassPath目录下的类库。如果用户没有自定义自己的类加载器,这个就是程序默认的类加载器。

另外,如果有需要的话,用户也可以自定义自己的类加载器(去继承ClassLoader类)。

我们也可以通过代码把类加载器打印出来:

public class TestClassLoader {
public static void main(String[] args) {
Object obj = new Object();
System.out.println(obj.getClass().getClassLoader()); TestClassLoader t = new TestClassLoader();
System.out.println(t.getClass().getClassLoader());
System.out.println(t.getClass().getClassLoader().getParent());
System.out.println(t.getClass().getClassLoader().getParent().getParent());
}
}

打印结果:

null
sun.misc.Launcher$AppClassLoader@58644d46
sun.misc.Launcher$ExtClassLoader@6d6f6e28
null

注意,上面第一行和第四行的null此处可不是空的意思,它代表的是启动类加载器。因为启动类加载器是用C++代码来实现的,严格来说不属于Java类,所以Java代码访问不到,故返回null。第二行是应用程序类加载器,第三行是扩展类加载器。

双亲委派机制

在介绍双亲委派机制之前,先观察一下以下代码能否正确运行:

//自己定义的一个 java.lang包
package java.lang; public class String {
public static void main(String[] args) {
String s = new String();
System.out.println(s);
}
}

以上代码,编译没有任何问题,但是运行时,却报错:

为什么提示在java.lang.String类中找不到main方法呢,我这明明不是定义了吗?其实,问题的关键就在于类加载遵循双亲委派机制。

类加载器有以下这样的层次关系:

当一个类在加载的时候,都会先委派它的父加载器去加载,这样一层层的向上委派,直到最顶层的启动类加载器。如果顶层无法加载(即找不到对应的类),就会一层层的向下查找,直到找到为止。 这就是类的双亲委派机制。

这样做有什么好处呢?这就相当于维护了一个有优先级的层级关系,即总是从最顶层的父加载器开始加载。这就如同,你工作中遇到了问题需要向上反馈,比如先反馈给小组长,然后小组长反馈给上级经理,最后经理反馈给boss。然后boss感觉这问题太简单了不需要他亲自出手,让经理自己解决吧,然后经理又向下交给小组长。小组长一看,这问题不算难,人也比较热心,于是就帮你把问题解决了。(可能例子不是太恰当哈,意思理解即可)

到此,我们就明白了为什么上边的代码会报错。因为双亲委派机制的存在,去加载我们自己定义的“java.lang.String”类的时候,会最终委派到顶层的启动类加载器,然后找到了rt.jar包下的“java.lang.String”。找到之后,就直接加载rt.jar包的String类(也就是我们经常使用的那个字符串类),不再去向下查找,也就加载不了我们自定义的String类了。由于,rt.jar包下的String类中确实没有main方法,所以才会有以上的报错信息。

我们可以试想一下,如果没有双亲委派机制的存在,那我这段代码是不是就可以执行成功了。如果这样的话,岂不是说明我可以随意覆盖rt.jar包中的类(如String,Integer类等)。这样的话将会使程序陷入混乱,Java核心包中的类的安全也无法保证。

Java类加载器和双亲委派机制的更多相关文章

  1. Java虚拟机类加载器及双亲委派机制

    所谓的类加载器(Class Loader)就是加载Java类到Java虚拟机中的,前面<面试官,不要再问我"Java虚拟机类加载机制"了>中已经介绍了具体加载class ...

  2. 【Java_基础】java类加载过程与双亲委派机制

    1.类的加载.连接和初始化 当程序使用某个类时,如果该类还未被加载到内存中,则系统会通过加载.连接.初始化三个步骤来对类进行初始化.如果没有意外,jvm将会连续完成这三个步骤,有时也把这三个步骤统称为 ...

  3. Java 基础 类加载器和双亲委派机制 学习笔记

    转自博客:https://blog.csdn.net/weixin_38118016/article/details/79579657 文章不是我写的,但是感觉写的挺通俗易懂的,然后防止以后丢失,就转 ...

  4. 深入JVM系列(三)之类加载、类加载器、双亲委派机制与常见问题

    一.概述   定义:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型.类加载和连接的过程都是在运行期间完成的. 二. 类的 ...

  5. java类加载过程以及双亲委派机制

    前言:最近两个月公司实行了996上班制,加上了熬了两个通宵上线,状态很不好,头疼.牙疼,一直没有时间和精力写博客,也害怕在这样的状态下写出来的东西出错.为了不让自己荒废学习的劲头和习惯,今天周日,也打 ...

  6. java类加载器和双亲委派模型

    一. 类加载器 ClassLoader即常说的类加载器,其功能是用于从Class文件加载所需的类,主要场景用于热部署.代码热替换等场景. 系统提供3种的类加载器:Bootstrap ClassLoad ...

  7. @Java类加载器及双亲委派模型

    类与类加载器 虚拟机设计团队把类加载阶段的"通过一个类的全限定名来获取此类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个 ...

  8. JVM类加载机制详解(二)类加载器与双亲委派模型

    在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可 ...

  9. 类文件的结构、JVM 的类加载过程、类加载机制、类加载器、双亲委派模型

    一.类文件的结构 我们都知道,各种不同平台的虚拟机,都支持 "字节码 Byte Code" 这种程序存储格式,这构成了 Java 平台无关性的基石.甚至现在平台无关性也开始演变出 ...

随机推荐

  1. 洛谷$P2153\ [SDOI2009]$ 晨跑 网络流

    正解:网络流 解题报告: 传送门$QwQ$ 题目好长昂,,,大概概括下$QwQ$.就说有$n$个节点$m$条边,然后要求每次走的路径都不一样,问最多能走多少次,然后在次数最多的前提下问路径最短是多少$ ...

  2. js中的事件冒泡

    事件冒泡和阻止事件冒泡: 事件冒泡的原理:从实际操作的元素(事件)向上级父元素一级一级执行下去,直到达到document/window,冒泡过程结束.例如:假设我有一个 div 盒子,里面嵌套了1个子 ...

  3. spring cloud微服务快速教程之(四)熔断器(Hystrix)及其工具(Dashboard、Turbine)

    0-为什么需要熔断器 在分布式系统中,各个服务相互调用相互依赖,如果某个服务挂了,很可能导致其他调用它的一连串服务也挂掉或者在不断等待中耗尽服务器资源,这种现象称之为雪崩效应: 未来防止系统雪崩,熔断 ...

  4. 配置ca服务器和http,mail加密

    一·CA介绍 certificate authority   数字证书授权中心 被通信双方信任的.独立的第三方机构 负责证书颁发.验证.撤销等管理 数字证书 经证书授权中心数字签名的包含公开密钥拥有者 ...

  5. 15.Python文本转化语音方法

    1.用pywin32模块来将文本转化为语音 通过pip install pywin32安装模块,pywin32是个万金油的模块,太多的场景使用到它,但在文本转语音上,它却是个青铜玩家,简单无脑但效果不 ...

  6. 记录一下第一次用markdown写博客回滚过程

    前面写博客,一直用的是博客园的TinyMCE编辑器, 今天不知道哪根筋搭牢了,想试试用Markdown写. 于是在“选项”里面把默认编辑器修改为“Markdown”,鉴于本人有一定的Markdown基 ...

  7. python可变对象

    - 每个对象中都保存了三个数据: id(标识) type(类型) value(值) - 列表就是一个可变对象 a = [1,2,3] - a[0] = 10 (改对象) - 这个操作是在通过变量去修改 ...

  8. C# HttpWebRequest传递参数多种方式混合使用

    在做CS调用第三方接口的时候遇到了这样的一个问题,通过PSOTman调试需要分别在parmas.Headers.Body里面同时传递参数.在网上查询了很多资料,以此来记录一下开发脱坑历程. POSTm ...

  9. sg函数的学习

    1 .anti-nim 2 . 可以拆分的

  10. Go 每日一库之 viper

    简介 上一篇文章介绍 cobra 的时候提到了 viper,今天我们就来介绍一下这个库. viper 是一个配置解决方案,拥有丰富的特性: 支持 JSON/TOML/YAML/HCL/envfile/ ...