【JAVA基础】JVM之类加载--双亲委派机制

目录

      • 1. 类加载的过程
        • 描述:
        • 看图:
        • 解释:
      • 2. 那么类加载器都有哪些呢
      • 3. 双亲委派机制
        • 3.1 双亲委派机制的过程
        • 3.2 图看委派过程
        • 3.3 为什么要设计双亲委派机制
      • 4. 自定义类加载器
        • 4.1 如何定义自己的类加载器?

1. 类加载的过程

描述:

我们写的.java文件通过编译成字节码文件.class文件,然后再通过我们的类加载器:Class Loader,反射以后,类模板存在方法区,把实例化的对象存在堆里;

看图:

在这里插入图片描述
对象的hashcode值

在这里插入图片描述

解释:
  • 从图中我们可以看出,从同一个类模板new出来三个对象(实例化过程)car1、car2、car3,而他们通过car1.hashCode(); car2.hashCode(); car3.hashCode()得到的hashCode码是不一样的(说明通过new关键字得到的对象不一样);
  • 但是通过 car1.getClass();car2.getClass();car3.getClass();得到的类模板是一样的。(说明是从同一个类模板new出来对象)

总结:

  • 对象. getClass()->获得 类模板;
  • 类模板. getClassLoader()->获得 类加载器

2. 那么类加载器都有哪些呢

类加载器主要分为四种:

  • 1.虚拟机自带的加载器
  • 2.根加载器(启动类加载器)(BootstrapClassloader)
  • 3.扩展类加载器(ExtClassloader) (JKD1.8之后为PlatformClassLoader平台类加载器 )
  • 4.应用程序类加载器(AppClassLoader)一般来说,Java 应用的类都是由它来完成加载的

扩展类加载器(Extension ClassLoader)和 应用程序类加载器(Application ClassLoader)是继承自抽象类java.lang.ClassLoader。

需要注意的是:各个类加载器之间是组合关系,并非继承关系

3. 双亲委派机制

那么到底该有哪个类去加载呢 ?所以我们在这引出双亲委派机制;

3.1 双亲委派机制的过程

一句话:向上委派,上面能加载就会加载;

  • 类加载器受到加载类的请求
  • 然后将这个请求向上委托给父类加载器去完成,一直向上委托:
    App -> Platform -> Bootstrap 直至到根加载器-Bootstrap
  • 根加载器Bootstrap会检查是否能加载当前这个类,(比如java.lang包下的所有类,根加载器都能加载);
    • 若能加载就由根加载器来加载这个类,加载到此结束;
    • 若不能加载,则才向下传递 Bootstrap -> Platform -> App直至有加载器来加载,不然就会报错;比如ClassNotFound

一般来说,Java 应用的类都是由AppClassLoader来完成加载的

总结

如果一个类加载器收到了类加载的请求,它首先不会自己尝试去加载这个类,而是把这个请求委派给父类加载器,每一个层次的类加载器都是加此,因此所有的加载请求最终到达顶层的启动类加载器,只有当父类加载器反馈自己无法完成加载请求时,子类加载器才会尝试自己去加载。

3.2 图看委派过程

在这里插入图片描述

从上图中我们就更容易理解了:

当一个.class这样的文件要被加载时。不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。

如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上。

注意这个类似递归的过程,直到到达Bootstrap classLoader之前,都是在检查是否加载过,并不会选择自己去加载。直到BootstrapClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException

那么有人就有下面这种疑问了?
为什么要有这种机制?

3.3 为什么要设计双亲委派机制

这种设计的好处:

  • 可以确保安全性。
    如果有人想替换系统级别的类:如String.java,篡改它的实现。双亲委派机制可以保证所有的Java类库都是由启动类加载器加载Bootstrap classLoader,从一定程度上防止了危险代码的植入;
  • 可以避免重复加载
    当父亲已经加载了该类的时候,就没有必要让子加载器再加载一次;

面试常问
问: 比如我们自己重新定义一个完全和String同包名的类: java.lang.String类,那么此时jdk加载的是系统自己的String还是我们的String?

答案:当然是系统自己的String类, 也就是说:我们自己写的java.lang.String的类,是不可以替换调JDK本身的类。
为什么呢?虽然和双亲委派机制有关系,但不是非常的准确。因为双亲委托派机制是可以打破的,我们完全可以自己写一个classLoader来加载自己写的java.lang.String类,但是我们会发现也不会加载成功;
真正的原因:
因为针对java.*开头的类,jvm的实现中已经保证了必须由Bootstrap classLoader ,也就是我们的根加载器来加载。

具体描述:
在加载某个类时,优先使用父类加载器加载。如果我们自定义了java.lang.String这个类, 那么该自定义String类使用的加载器应是是AppClassLoader,根据双亲委派原理, AppClassLoader加载器的父类为ExtClassLoader,所以这时加载String使用的类加载器是ExtClassLoader, 但是类加载器ExtClassLoader在jre/lib/ext目录下没有找到String.class类。 然后使用ExtClassLoader父类的加载器BootStrap, 父类加载器BootStrap在jre/lib目录的rt.jar找到了String.class,将其加载到内存中。而jre/lib目录下的 String类 就是我们jdk自己的类。

4. 自定义类加载器

问: 既然JVM已经提供了默认的类加载器,为什么还要自已来定义类加载器呢?

答: 因为Java中提供的默认ClassLoader,只加载指定目录下的jar和class,如果我们想加载其它位置的类或jar时,比如:我们想要加载网络上的一个.class文件,加载到内存之后,我们想要调用这个类中的方法实现自己的业务逻辑。在这样的情况下,默认的ClassLoader就不能满足我们的需求了,所以需要定义自己的ClassLoader。

4.1 如何定义自己的类加载器?

定义自已的类加载器分为两步:

  • 继承java.lang.ClassLoader

  • 重写父类的findClass方法

问: 为什么只重写findClass方法?

答: 因为JDK已经在loadClass方法中帮我们实现了ClassLoader搜索类的算法,当在loadClass方法中搜索不到类时,loadClass方法就会调用findClass方法来搜索类,所以我们只需重写该方法即可。

但是,如没有特殊的要求,一般不建议重写loadClass搜索类的算法。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

宋仕强论道之华强北购物中心shopping mall(四十一)

购物中心shopping mall是上世纪在美国流行传到我国的概念,即很大的综合性的百货日用品交易中心,服务覆盖半径大概是周边3-5公里或者半个小时车程的居民,(美国地广人稀服务的范围会更大),作为一个大型商业综…

这些代码对比工具,你都知道吗?屎山别怕

在程序开发的过程中,程序员会经常对源代码以及库文件进行代码对比,在这篇文章里我们向大家介绍六款程序员常用的代码比较工具 WinMerge WinMerge是一款运行于Windows系统下的文件比较和合并工具,使用它可以非常方便地比较多个文档内容&#…

odoo17基础培训1-odoo开发基础知识准备以及odoo17开发环境安装

odoo17基础培训 一、odoo开发基础知识准备以及odoo17开发环境安装 1、odoo是什么? 当我介绍客户使用odoo系统作为业务管理平台时,有时会被问到Odoo是什么? 简单点,可以这么说: Odoo是一套完整的系统,是…

深入探讨:开发连锁餐饮APP的关键技术要点

时下,开发一款功能强大、用户友好的连锁餐饮APP成为许多餐饮企业的当务之急。在本文中,我们将深入探讨开发连锁餐饮APP的关键技术要点,涵盖了前端、后端以及数据库等方面。 一、前端开发 前端是用户与APP交互的入口,因此设计良好…

Oladance、南卡、Cleer开放式耳机怎么样?全方位测评大PK!

​开放式耳机作为新兴的音频设备领域中备受欢迎的选择,但市场上琳琅满目的产品汇集了质量千差万别的耳机,其中存在着一些粗制滥造的产品。身为一位音频设备测评博主,我经常收到有关哪个品牌的开放式耳机质量好的疑问。面对市面上众多选择&…

JAVA微信公众号开发平台源码带数据库

JAVA微信公众号开发平台源码带数据库 前台框架: easyui 后台框架: SpringMVChibernate

Proteus仿真stm32f103r6输出PWM/正弦波

资料下载地址:Proteus仿真stm32f103r6输出PWM/正弦波 一、仿真图 Proteus仿真stm32f103r6输出PWM/正弦波 二、程序 #include "pbdata.h"u16 fre; void RCC_Configuration(void); void GPIO_Configuration(void); void TIM3_Configuration();void Dela…

C++学习笔记——继承和动态内存分配

目录 一、继承 二、动态内存分配 三、继承的细节 四、动态内存分配细节 五、一个动物园管理系统 继承和动态内存分配是C中两个重要的概念 一、继承 继承是C中面向对象编程的一个重要特性,它允许我们创建一个新类,该类从现有的类中继承属性和方法&…

oracle-事务一系列理解

一个事务开始后,会被分配一个唯一的id号,xid,xid不仅是一个编号也是一个地址。 事务表 存在undo表空间的某一个段的段头块,最多存放47个事务,事务开始的时候,先将信息写入这个表,所以一个undo段…

【android】rk3588-android-bt

文章目录 蓝牙框架HCI接口蓝牙VENDORLIBvendorlib是什么 代码层面解读vendorlib1、 vendorlib实现,协议栈调用2、协议栈实现,vendorlib调用(回调函数)2.1、 init函数2.2、BT_VND_OP_POWER_CTRL对应处理2.3、BT_VND_OP_USERIAL_OPE…

Golang的API项目快速开始

开启一个简单的API服务。 golang的教程网上一大堆,官网也有非常详细的教程,这里不在赘述这些基础语法教程,我们意在快速进入项目开发阶段。 golang好用语法教程传送门: m.runoob.com/go/ 编写第一个API 前提:按照上一…