类加载器系列(一)——类加载器的作用和分类

简介: 类加载器系列(一)——类加载器的作用和分类

概述


准备写一个类加载器相关的系列文章,本篇作为第一篇内容,主要阐述类加载器的作用,同时针对类加载器做一个分类说明。


类加载器的作用


众所周知,我们写的java代码通过前端编译器最终变成class文件,那么磁盘上的class文件是怎么加载到jvm中的呢?答案当然是类加载器ClassLoader。 ClassLoader是Java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader负责通过各种方式将Class信息的二进制数据流读入JVM内部,转换为一个与目标类对应的java.lang.Class对象实例。然后交给Java虚拟机进行链接、初始化等操作。因此,ClassLoader在整个装载阶段,只能影响到类的加载,而无法通过ClassLoader去改变类的链接和初始化行为。

image.png


类加载器加载时机


在什么情况下类加载器会加载类,分为两种情况:显示加载和隐式加载。

显示加载

代码中通过调用ClassLoader加载class对象,如直接使用Class.forName(name)或this.getClass().getClassLoader().loadClass()加载class对象。

隐式加载

隐式加载是通过虚拟机自动加载到内存中,如在加载某个类的class文件时,该类的class文件中引用了另外一个类的对象,那么被引用的类也会被加载到JVM中。

// 隐式加载
Person person = new Person();
//显式加载,并初始化
Class clazz=Class.forName("com.alvin.classloader.Person");
//显式加载,但不初始化
ClassLoader.getSystemClassLoader().loadClass("com.alvin.classloader.Person");

启动参数添加-XX:+TraceClassLoading可以查看类加载器加载的所有类。

1671107808728.jpg


类加载器的分类和关系


并不是所有的类都是由同一个类加载器加载的,广义的来说,JVM类加载器分为两大类,分别为启动类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)。

JAVA虚拟机规范定义,所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器。比如jdk内置的扩展类加载器(Extension ClassLoader)和应用类加载器(Application ClassLoader)都属于自定义类加载器,他们之间的关系如下:

1671107818233.jpg

  • 除了顶层的启动类加载器外,其余的类加载器都应当有自己的“父类”加载器。
  • 不同类加载器看似是继承(Inheritance)关系,实际上是包含关系。在下层加载器中,包含着上层加载器的引用。


启动类加载器(Bootstrap ClassLoader)


  • 这个类加载使用C/C++语言实现的,嵌套在JVM内部。
  • 它用来加载Java的核心库(JAVAHOME/jre/lib/rt.jar或sun.boot.class.path路径下的内容)。用于提供JVM自身需要的类。也就是说只加载包名为java、javax、sun等开头的类。
  • 并不继承自java.lang.ClassLoader,没有父加载器。
  • 被启动类加载器加载的类,获取他们的类加载器为null, 也就是说启动类加载器没有这个java类,因为她是C/C++实现的。
System.out.println("**********启动类加载器加载的目录**********");
URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (URL url : urLs) {
    System.out.println(url.toExternalForm());
}
System.out.println("**********java.lang.String的类加载是什么?**********");
ClassLoader classLoader = String.class.getClassLoader();
// null, 启动类加载器获取到的是null
System.out.println(classLoader);

输出结果:

1671107830885.jpg


扩展类加载器(ExtClassLoader)


  • Java语言编写,继承于ClassLoader类, 由sun.misc.Launcher$ExtClassLoader实现。它的父类加载器为启动类加载器。
  • 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。
System.out.println("***********扩展类加载器加载目录***********");
String extDirs = System.getProperty("java.ext.dirs");
for (String path : extDirs.split( ";")){
    System.out.println(path);
}
// 从上面的路径中随意选择一个类,来看看他的类加载器是什么:扩展类加载器
ClassLoader classLoader1 = sun.security.ec.ECKeyFactory.class.getClassLoader();
System.out.println(classLoader1);  //sun.misc. Launcher$ExtCLassLoader@1540e19d
// 扩展类的父类加载器为启动类加载器
System.out.println(classLoader1.getParent()); // null

输出结果:

1671107858246.jpg


系统类加载器(AppClassLoader)


  • Java语言编写,继承于ClassLoader类, 由sun.misc.Launcher$AppClassLoader。它的父类加载器为扩展类加载器。
  • 它加载环境变量classpath和系统属性java.class.path 指定路径下的类库,比如我们自己写的java类就是由系统类加载器加载的。
  • 通过ClassLoader的getSystemClassLoader()方法可以获取到该类加载器。
// 自己写的Person类
ClassLoader classLoader = com.alvin.classloader.Person.class.getClassLoader();
System.out.println(classLoader);  //sun.misc.Launcher$AppClassLoader@18b4aac2
// 应用类加载器的父类是扩展类加载器
System.out.println(classLoader.getParent()); //sun.misc.Launcher$ExtClassLoader@266474c2

以上就是java中内置的一些类加载器,那他们是如何协同工作的呢,这就涉及到一个双亲委派机制,在后面的文章中详细介绍。


类加载器特点


  • 类的唯一性,对于任意一个类,都需要由加载它的类加载器和这个类本身一同确认其在Java虚拟机中的唯一性。也就是说,比较两个类是否相等,只有在这两个类是由同一个类加载器加载的前提下才有意义。
  • 可见性,子类加载器可以访问父类加载器加载的类型,反之不行。也就是可以调用AppClassLoader中loadClass加载我们自己写的Person类,但是不能用ExtClassLoader加载我们写的Person类。
  • 单一性,已经被父类加载器加载过的类,不会重复加载,可以直接使用。


小结


本文是类加载器的一个入门篇,介绍了类加载器的作用和分类,并对java内置的各个类加载器做了一个说明。在后面,我们详细介绍各个类加载器是如何协同工作,完成类的加载。

目录
相关文章
|
前端开发 安全 Java
类加载器原理
一、类加载 二、链接 三、初始化
类加载器原理
|
4月前
|
Java
类加载器以及类的加载过程
这篇文章讨论了Java中的类加载器机制以及类的加载过程。
类加载器以及类的加载过程
|
3月前
|
Arthas 前端开发 Java
类加载器 超详解:什么是类加载器,类加载器作用及应用场景,类加载时机,类加载的完整过程,类加载器分类
类加载器 超详解:什么是类加载器,类加载器作用及应用场景,类加载时机,类加载的完整过程,类加载器分类
类加载器 超详解:什么是类加载器,类加载器作用及应用场景,类加载时机,类加载的完整过程,类加载器分类
|
2月前
|
缓存 前端开发 Java
JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
这篇文章详细介绍了JVM中ClassLoader的工作原理,包括类加载器的层次结构、双亲委派机制、类加载过程、自定义类加载器的实现,以及如何打破双亲委派机制来实现热部署等功能。
53 3
|
3月前
|
Arthas Java 测试技术
JVM —— 类加载器的分类,双亲委派机制
类加载器的分类,双亲委派机制:启动类加载器、扩展类加载器、应用程序类加载器、自定义类加载器;JDK8及之前的版本,JDK9之后的版本;什么是双亲委派模型,双亲委派模型的作用,如何打破双亲委派机制
JVM —— 类加载器的分类,双亲委派机制
|
7月前
|
前端开发 Java 开发者
JVM类加载器的分类以及双亲委派机制
JVM类加载器的分类以及双亲委派机制
|
7月前
|
存储 缓存 前端开发
类加载与类加载器概述
类加载与类加载器概述
60 6
|
存储 安全 Java
类加载器与类的加载过程
类加载器与类的加载过程
|
缓存 前端开发 Java
37. 请你详细说说类加载流程,类加载机制及自定义类加载器 中
37. 请你详细说说类加载流程,类加载机制及自定义类加载器 中
127 0
37. 请你详细说说类加载流程,类加载机制及自定义类加载器 中
|
Java
37. 请你详细说说类加载流程,类加载机制及自定义类加载器 下
37. 请你详细说说类加载流程,类加载机制及自定义类加载器 下
99 0