系列阅读

  • Java基础:类加载器
  • Java基础:反射
  • Java基础:注解
  • Java基础:动态代理

1. 什么是类加载器

类加载器就是用来加载类的东西!类加载器也是一个类:ClassLoader

类加载器可以被加载到内存,是通过类加载器完成的!Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:

  • BootStrap:引导类加载器,加载rt.jar中的类
  • ExtClassLoader:扩展类加载器,加载lib/ext目录下的类
  • AppClassLoader:系统类加载器,加载CLASSPATH下的类,即我们写的类,以及第三方提供的类

类加载器之间存在上下级关系,系统类加载器的上级是扩展类加载器,而扩展类加载器的上级是引导类加载器

类加载器也是Java类,因为其它java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap。

Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载

2. 类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

2.1 加载

就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。

2.2 连接

  • 验证:是否有正确的内部结构,并和其他类协调一致
  • 准备:负责为类的静态成员分配内存,并设置默认初始化值
  • 解析:将类的二进制数据中的符号引用替换为直接引用

2.3 初始化

类会在首次被“主动使用”时执行初始化,为类(静态)变量赋予正确的初始值。在Java代码中,一个正确的初始值是通过类变量初始化语句或者静态初始化块给出的。

初始化一个类包括两个步骤:

  • 如果类存在直接父类的话,且直接父类还没有被初始化,则先初始化其直接父类
  • 如果类存在一个初始化方法,就执行此方法

注:初始化接口并不需要初始化它的父接口。

3. 类初始化时机

  • 创建类的实例
  • 访问类的静态变量,或者为静态变量赋值
  • 调用类的静态方法
  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类

4. 类加载器

负责将.class文件加载到内在中,并为之生成对应的Class对象。虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。

4.1 类加载器的组成

  • BootstrapClassLoader 根类加载器
  • ExtensionClassLoader 扩展类加载器
  • SysetmClassLoader 系统类加载器

4.2类加载器的作用

1、Bootstrap ClassLoader 根类加载器

也被称为引导类加载器,负责Java核心类的加载,比如System,String等。在JDK中JRE的lib目录下rt.jar文件中。

2、Extension ClassLoader 扩展类加载器

负责JRE的扩展目录中jar包的加载。在JDK中JRE的lib目录下ext目录

3、Sysetm ClassLoader 系统类加载器

负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。通过这些描述我们就可以知道我们常用的东西的加载都是由谁来完成的。到目前为止我们已经知道把class文件加载到内存了,那么,如果我们仅仅站在这些class文件的角度,我们如何来使用这些class文件中的内容呢?这就是我们反射要研究的内容。

5. JVM眼中的相同的类

在JVM中,不可能存在一个类被加载两次的事情!一个类如果已经被加载了,当再次试图加载这个类时,类加载器会先去查找这个类是否已经被加载过了,如果已经被加载过了,就不会再去加载了。

但是,如果一个类使用不同的类加载器去加载是可以出现多次加载的情况的!也就是说,在JVM眼中,相同的类需要有相同的class文件,以及相同的类加载器。当一个class文件,被不同的类加载器加载了,JVM会认识这是两个不同的类,这会在JVM中出现两个相同的Class对象!甚至会出现类型转换异常!

6. 类加载器的委托机制

首先委托类加载器的父类去加载,如果父类无法加载则自己加载

当系统类加载器去加载一个类时,它首先会让上级去加载,即让扩展类加载器去加载类,扩展类加载器也会让它的上级引导类加载器去加载类。如果上级没有加载成功,那么再由自己去加载!

例如我们自己写的Person类,一定是存放到CLASSPATH中,那么一定是由系统类加载器来加载。当系统类加载器来加载类时,它首先把加载的任务交给扩展类加载去,如果扩展类加载器加载成功了,那么系统类加载器就不会再去加载。这就是代理模式了!

相同的道理,扩展类加载器也会把加载类的任务交给它的“上级”,即引导类加载器,引导类加载器加载成功,那么扩展类加载器也就不会再去加载了。引导类加载器是用C语言写的,是JVM的一部分,它是最上层的类加载器了,所以它就没有“上级了”。它只负责去加载“内部人”,即JDK中的类,但我们知道Person类不是我们自己写的类,所以它加载失败。

当扩展类加载器发现“上级”不能加载类,它就开始加载工作了,它加载的是lib\ext目录下的jar文件,当然,它也会加载失败,所以最终还是由系统类加载器在CLASSPATH中去加载Person,最终由系统类加载器加载到了Person类。

代理模式保证了JDK中的类一定是由引导类加载加载的!这就不会出现多个版本的类,这也是代理模式的好处。

6.1 类加载器之间的父子关系和管辖范围图

7. 自定义类加载器

我们也可以通过继承ClassLoader类来完成自定义类加载器,自定义类加载器的目的一般是为了加载网络上的类,因为这会让class在网络中传输,为了安全,那么class一定是需要加密的,所以需要自定义的类加载器来加载(自定义的类加载器需要做解密工作)。

ClassLoader加载类都是通过loadClass()方法来完成的,loadClass()方法的工作流程如下:

  • 调用findLoadedClass()方法查看该类是否已经被加载过了,如果该没有加载过,那么这个方法返回null

  • 判断findLoadedClass()方法返回的是否为null,如果不是null那么直接返回,这可以避免同一个类被加载两次

  • 如果findLoadedClass()返回的是null,那么就启动代理模式(委托机制),即调用上级的loadClass()方法,获取上级的方法是getParent(),当然上级可能还有上级,这个动作就一直向上走

  • 如果getParent().loadClass()返回的不是null,这说明上级加载成功了,那么就加载结果

  • 如果上级返回的是null,这说明需要自己出手了,这时loadClass()方法会调用本类的findClass()方法来加载类

  • 这说明我们只需要重写ClassLoader的findClass()方法,这就可以了!如果重写了loadClass()方法覆盖了代理模式!

OK,通过上面的分析,我们知道要自定义一个类加载器,只需要继承ClassLoader类,然后重写它的findClass()方法即可。那么在findClass()方法中我们要完成哪些工作呢?

  • 找到class文件,把它加载到一个byte[]中;
  • 调用defineClass()方法,把byte[]传递给这个方法即可。

loadClass()方法的实现代码

protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {Class<?> clazz = findLoadedClass(className);if (clazz == null) {ClassNotFoundException suppressed = null;try {clazz = parent.loadClass(className, false);} catch (ClassNotFoundException e) {suppressed = e;}if (clazz == null) {try {clazz = findClass(className);} catch (ClassNotFoundException e) {e.addSuppressed(suppressed);throw e;}}}return clazz;
}

自定义类加载器FileSystemClassLoader

public class FileSystemClassLoader extends ClassLoader {private String classpath;public FileSystemClassLoader() {}public FileSystemClassLoader(String classpath) {this.classpath = classpath;}@Overridepublic Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] datas = getClassData(name);if(datas == null) {throw new ClassNotFoundException("类没有找到:" + name);}return this.defineClass(name, datas, 0, datas.length);} catch (IOException e) {e.printStackTrace();throw new ClassNotFoundException("类找不到:" + name);}}private byte[] getClassData(String name) throws IOException {name = name.replace(".", "\\") + ".class";File classFile = new File(classpath, name);return FileUtils.readFileToByteArray(classFile);}
}
ClassLoader loader = new FileSystemClassLoader("F:\\classpath");
Class clazz = loader.loadClass("cn.itcast.utils.CommonUtils");
Method method = clazz.getMethod("md5", String.class);
String result = (String) method.invoke(null, "qdmmy6");
System.out.println(result);

8. ClassLoader

方法 说明
getParent() 获取上级类加载器
loadClass() 实现了类加载的加载流程,也就是算法框架
findLoadedClass() 查看该类是否被加载过
findClass() 真正去加载类,自定义类加载器需要重写的方法
defineClass() 把Class的字节数组byte[]转成Class

Java基础:类加载器相关推荐

  1. java基础类加载器_Java基础之类加载器

    1. 什么是类加载器? 加载类的工具. 2. Java虚拟机中可以安装多个类加载器,系统默认三个主要的类加载器,每个类负责加载特定位置的类: BootStrap,ExtClassLoader,AppC ...

  2. Java基础——类加载机制及原理

    一.什么是类的加载? 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结 ...

  3. OSGi 规范和框架 OSGi框架类加载机制 Java默认类加载器机制和OSGI类加载器机制比较

    一.OSGi 规范 OSGi(Open Service Gateway Initiative) 技术是 Java 动态化模块化系统的一系列规范.OSGi 一方面指维护 OSGi 规范的 OSGi Al ...

  4. Java 自定义类加载器教程

    文章目录 Java 自定义类加载器教程 loadClass findClass defineClass 函数调用过程 Java 自定义类加载器教程 除了在面试中遇到类的加载器的概率会高外,在实际的工作 ...

  5. java中的类加载器有,Java自定义的类加载器,java自定义加载,在java中类加载器有以...

    Java自定义的类加载器,java自定义加载,在java中类加载器有以 在java中类加载器有以下几种java虚拟机自带的加载器 1)根类加载器(Bootstrap,c++实现)2)扩展类加载器(Ex ...

  6. 2099年了,你知道什么是Java的类加载器嘛?

    Java的类加载器 作用 编译器先把java文件编译成class字节码文件 ClassLoad会把字节码文件转换成jvm中的Class对象 jvm再把class对象转成实例对象 ClassLoad在j ...

  7. java类二次加载_深入理解java之类加载器

    一.类与类加载器 类加载器:实现加载阶段的第一步,通过一个类的全限定名来将这个类的二进制字节流加载进jvm. 类与类加载器:任意一个类唯一性都是由它本身和加载它的类加载器确定,两个类是否相等在它们是由 ...

  8. java安全——类加载器+字节码校验+安全管理器与访问权限

    [0]README 0.1)本文文字描述转自 core java volume 2,旨在学习 java安全 的相关知识: [1]类加载器 1)java 技术提供了以下3种确保安全的机制(mechani ...

  9. java的类加载器都有哪些_java类加载器包括哪些内容?树状结构示意图展示

    在我们科学技术与经济水平均高速发展的今天,掌握一门新兴技术对于每一个有志青年来说都是十分重要的.今天主要为大家详细介绍一下java的关键技术强化--类加载器,以及通过示意图展示它的结构. 首先为大家简 ...

  10. java的类加载器以及如何自定义类加载器

    ClassLoader作用 类加载流程的"加载"阶段是由类加载器完成的. 类加载器结构 结构:BootstrapClassLoader(祖父)–>ExtClassLoader ...

最新文章

  1. [通用技术]在不同语言中用协程实现全排列算法(C++/Lua/Python/C#)
  2. kivy 的on_touch_move和on_touch_down
  3. Mysql自动备份脚本
  4. android 介绍0
  5. 五大算法之三--贪心算法
  6. 信息奥赛一本通(1180:分数线划定)——插入排序
  7. iOS7应用开发6:UINavigation, UITabbar控制器的多态性
  8. sap委外采购订单冲销 102_SAP那些事-实战篇-68-谈谈SAP的库存设计理念
  9. C++设计模式::装饰模式or代理模式or面向切片编程(AOP)
  10. ntldr is missing什么意思应该如何解决
  11. Android Realm(数据库)
  12. 用数据告诉你出租车资源配置是否合理
  13. miui9android8.0xp框架,MIUI9MIUI10官方8.0/8.1刷入xp框架
  14. C/C++基础题029.DDD
  15. Cmake的重新编译
  16. HTML讲解(HTML结构及标签)
  17. 重大调整!高速限速标准将不再是120km/h
  18. SVG 的平移、旋转和缩放
  19. 澳式滋味一页俱全开启你的味蕾之旅
  20. 鸿蒙不用百度网盘,百度网盘限速有救了!官方新出2种方法,不用开会员

热门文章

  1. 企业部署Windows 7指南
  2. Linux下常用 60个命令
  3. 什么是物联网?—Vecloud 微云
  4. Kingbase金仓更改表空间
  5. 数字加字符串用,隔开
  6. JavaScript之图片操作3
  7. 洛谷 P1897电梯里的爱情 题解
  8. C++ 与 JAVA的不同点
  9. [团队公告]第二次技术交流主题征集
  10. FB高管:计划明年推出数字货币Diem和数字钱包Novi