类加载器详解

类加载器详解

回顾一下类加载过程

​ 开始介绍类加载器和双亲委派模型前,简单回顾一下类加载的过程

  • 类加载过程:加载->连接->初始化
  • 连接过程又可分为三步:验证->准备->解析

类加载过程

加载是类加载过程的第一步,主要完成下面三件事:

  1. 通过全类名获取定义此类的二进制字节流
  2. 将字节流锁代表的静态存储结构转化为方法去的运行时数据结构
  3. 再内存中生成一个代表该类的 Class 对象,作为犯法去这些数据的访问入口。

类加载器

​ 类加载器介绍

​ 类加载器从 JDK 1.0 就出席那了,最初芝士为了满足 Java Applet (已经被淘汰)的需要。后来慢慢成为 Java 程序中的一个重要组成部门,赋予了 Java 类可以被动态加载到 JVM 中并执行的能力。

​ 根据官方 API 文档的介绍:

A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a “class file” of that name from a file system.

Every Class object contains a reference to the ClassLoader that defined it.

Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; if the element type is a primitive type, then the array class has no class loader.

​ 翻译过来的大致意思是

​ 类加载器是一个负责加载类的对象。ClassLoader 是一个抽象类。给定类的二进制名称,类加载器应尝试定位或生成构成类定义的数据。典型的策略是将名称转化为文件名,然后从文件系统中读取该名称的 ”类文件“ 。

​ 每个 Java 类都有一个引用指向加载它的 ClassLoader 。不过,数组类不是通过 ClassLoader 创建的,而是JVM 再需要的时候自动创建的,数组类通过 getClassLoader() 方法获取 ClassLoader 的时候和该数组元素的 ClassLoader 是一致的

从上面的介绍可以看出:

  • 类加载器是一个负责加载类的对象,它用于实现类加载过程中的加载这一步
  • 每个 Java 类都有一个引用指向加载它的 ClassLoader
  • 数组类不是通过 ClassLoader 实现的,是由 JVM 直接实现的

​ 简单来说,**类加载器的主要作用就是加载 Java 类的字节码( .class 文件)到 JVM 中 (在内存中生成一个代表该类的 Class 对象)。 ** 字节码可以是 Java 源程序 ( .java 文件) 经过 javac 编译得来,也可以是通过工具动态生成或者通过网络下来得来

​ 其实除了加载类之外,类加载还可以加载 Java 应用所需的资源如文本、图像、配置文件、视频等等文件资源

类加载器加载规则

​ JVM 启动的时候,并不会一次加载所有的类,而是根据需要去动态加载。也就是说,大部分类在具体用到的时候才回去加载,这样对内存更友好。

​ 对于已经加载的类会被放在 ClassLoader 中。 在类加载的时候,系统会先首先判断当前类是否被加载过。已经被加载的类回直接返回,否则才会尝试加载。也就是说,对于一个类加载器来说,相同二进制名称的类只会被加载一次

类加载器总结

​ JVM 中内置了三个重要的 ClassLoader

  1. BootstrapClassLoader启动类加载器 ):最顶层的加载器,有 C++实现,通常表现为 null,并且没有父级,主要用来加载 JDK 内部的核心类库( %JAVA_HOME%/lib 目录下的 rt.jarresources.jarcharsets.jar 等 jar 包和类)以及被 -Xbootclasspath 参数指定的路径下的所有类。
  2. ExtensionClassLoader (扩展类加载器):主要负责加载 %JRE_HOME%/lib/ext 目录下的 jar 包和类以及被 java.ext.dirs 系统变量锁指定的路径下的类。
  3. AppClassLoader (应用程序类加载器):面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类

​ 除了这三种类加载器之外,用户还可以加入自定义的类加载器来进行扩展,以满足自己的特殊需求。就比如,我们可以对 Java 类的字节码( .class 文件)进行加密,加载时再利用自定义的类加载器对其解密。

类加载器层次关系图

除了 `BootstrapClassLoader` 是 JVM 自身的一部分之外,其他所有的类加载器都是在 JVM 外部实现的,并且全部继承自 `ClassLoader`  抽象类。这样做的好处是用户可以自定义类加载器,以便让应用程序自己去决定如何去获取所需的类。

​ 每个 ClassLoader 可以通过 getParent() 获取其父 ClassLoader ,如果获取到的父类加载器为 null 的话,那么该类是通过启动类加载器直接加载的。

自定义类加载器

​ 我们前面也说说了,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader。如果我们要自定义自己的类加载器,很明显需要继承 ClassLoader抽象类。

ClassLoader 类有两个关键的方法:

  • protected Class loadClass(String name, boolean resolve):加载指定二进制名称的类,实现了双亲委派机制 。name 为类的二进制名称,resolve 如果为 true,在加载时调用 resolveClass(Class<?> c) 方法解析该类。
  • protected Class findClass(String name):根据类的二进制名称来查找类,默认实现是空方法。

官方 API 文档中写到:

Subclasses of ClassLoader are encouraged to override findClass(String name), rather than this method.

建议 ClassLoader的子类重写 findClass(String name)方法而不是loadClass(String name, boolean resolve) 方法。

的子类重写 findClass(String name)方法而不是loadClass(String name, boolean resolve)` 方法。

​ 如果我们不想打破双亲委派模型,就重写 ClassLoader 类中的 findClass() 方法即可,无法被父类加载器加载的类最终会通过这个方法被加载。但是,如果想打破双亲委派模型则需要重写 loadClass() 方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值