Java三个类加载器及它们的相互关系

 更新时间:2021年06月07日 11:03:15   作者:cswhl  
Java在需要使用类别的时候,才会将类别加载,Java的类别载入是由类别载入器(Class loader)来达到的,预设上,在程序启动之后,主要会有三个类别加载器,文中详细介绍了这三个类加载器,需要的朋友可以参考下

一、什么是类加载器?

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

类加载器可以说是Java语言的一项创新,也是Java语言流行的重要原因之一,它最初是为了满足Java Applet的需求而开发出来的。虽然目前Java Applet技术基本上已经“死掉”,但类加载器却在类层次划分、OSGi、热部署、代码加密等领域大放异彩,成为了Java技术体系中一块重要的基石,可谓是失之桑榆,收之东隅。

类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用却远远不限于类加载阶段。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类,都拥有一个独立的类名称空间。这句话可以表达得更通俗一些:比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义。否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。

二、AppClassLoader系统类加载器

AppClassLoader应用类加载器,又称为系统类加载器,负责在JVM启动时,加载来自命令java中的classpath或者java.class.path系统属性或者CLASSPATH操作系统属性所指定的JAR类包和类路径

  • 获取当前类的类加载器:
public class AppClassLoaderTest {

    public static void main(String[] args) {
        System.out.println(ClassLoader.getSystemClassLoader());
    }

}

输出:

sun.misc.Launcher$AppClassLoader@73d16e93

这说明AppclassLoader是当前应用classpath所有类的加载器。

查看ClassLoader的源码可发现:在没有特定说明的情况下,用户自定义的任何类加载器都将该类加载器作为自定义类加载器的父加载器.

  • 通过执行下面的代码即可获得classpath的加载路径:
String classPath = System.getProperty("java.class.path");
for (String path : classPath.split(";")) {
    System.out.println(path);
}

输出:

.

通常是当前执行字节码的路径。

  • main函数的类的加载就是使用AppClassLoader加载器进行加载的,而AppClassLoader的父加载器是ExtClassLoader:
public class AppClassLoaderTest {

    public static void main(String[] args) {
        ClassLoader classLoader = Test.class.getClassLoader();
        System.out.println(classLoader);
        System.out.println(classLoader.getParent());
    }

    private static class Test {

    }

}

输出:

sun.misc.Launcher$AppClassLoader@73d16e93 
sun.misc.Launcher$ExtClassLoader@15db9742 

三、ExtClassLoader扩展类加载器

ExtClassLoader称为扩展类加载器,主要负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目录下的所有jar包或者由java.ext.dirs系统属性指定的jar包.放入这个目录下的jar包对AppClassLoader加载器都是可见的(因为ExtClassLoader是AppClassLoader的父加载器,并且Java类加载器采用了委托机制).

  • ExtClassLoader的类扫描路径通过执行下面代码来看一下:
public class ExtClassLoaderTest {
	
	public static void main(String[] args) {
		String extDirs = System.getProperty("java.ext.dirs");
		for (String path : extDirs.split(";")) {
			System.out.println(path);
		}
	}
}

执行结果如下:

D:\TOOLS\JAVA\lib\ext 
C:\WINDOWS\Sun\Java\lib\ext 

  • 从上面的路径中随意选择一个类,来看看它的类加载器是什么:
public class ExtClassLoaderTest {
	
	public static void main(String[] args) {
		ClassLoader classLoader = sun.security.ec.SunEC.class.getClassLoader();
		System.out.println(classLoader);
		System.out.println(classLoader.getParent());
	}
}

输出:

sun.misc.Launcher$ExtClassLoader@30f39991 
null 

从输出结果可知ExtClassLoader的父加载器为null

四、BootstrapClassLoader启动类加载器

启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等

  • 通过如下程序获得该类加载器从哪些地方加载了相关的jar或class文件:
import java.net.URL;

public class BootstraplassLoaderPath {
	
	public static void main(String[] args) {
		URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();
		for (URL url : urLs) {
    	System.out.println(url.toExternalForm());
		}
	}
}

输出:

file:/D:/TOOLS/JAVA/lib/resources.jar
file:/D:/TOOLS/JAVA/lib/rt.jar
file:/D:/TOOLS/JAVA/lib/sunrsasign.jar
file:/D:/TOOLS/JAVA/lib/jsse.jar
file:/D:/TOOLS/JAVA/lib/jce.jar
file:/D:/TOOLS/JAVA/lib/charsets.jar
file:/D:/TOOLS/JAVA/lib/jfr.jar
file:/D:/TOOLS/JAVA/classes

  • 从rt.jar中选择String类,看一下String类的类加载器是什么:
public class stringBootstraplassLoaderTest {
	
	public static void main(String[] args) {
		ClassLoader classLoader = String.class.getClassLoader();
    System.out.println(classLoader);
	}
}

输出:

null

由于BootstrapClassLoader对Java不可见,所以返回了null,我们也可以通过某一个类的加载器是否为null来作为判断该类是不是使用BootstrapClassLoader进行加载的依据。
另外上面提到ExtClassLoader的父加载器返回的是null,那是否说明ExtClassLoader的父加载器是BootstrapClassLoader.

Bootstrap ClassLoader是由C/C++编写的,它本身是虚拟机的一部分,所以它并不是一个JAVA类,也就是无法在java代码中获取它的引用,JVM启动时通过Bootstrap类加载器加载rt.jar等核心jar包中的class文件,之前的int.class,String.class都是由它加载。

五、加载器关系总结

JVM初始化sun.misc.Launcher并创建Extension ClassLoader和AppClassLoader实例。并将ExtClassLoader设置为AppClassLoader的父加载器,Bootstrap则是ExtClassLoader的父加载器.
关系图如下:

六、参考资料

1.Java类加载器
2.一看你就懂,超详细java中的ClassLoader详解

到此这篇关于Java三个类加载器及它们的相互关系的文章就介绍到这了,更多相关Java类加载器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Idea开发工具之SpringBoot整合JSP的过程

    Idea开发工具之SpringBoot整合JSP的过程

    最近在学习SpringBoot,看到SpringBoot整合jsp,顺带记录一下。本文通过图文实例相结合给大家讲解SpringBoot整合JSP的过程,感兴趣的朋友一起看看吧
    2021-09-09
  • MyBatis之传入参数为list、数组、map的写法

    MyBatis之传入参数为list、数组、map的写法

    这篇文章主要介绍了MyBatis之传入参数为list、数组、map的写法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • springboot利用aop实现接口异步(进度条)的全过程

    springboot利用aop实现接口异步(进度条)的全过程

    我们在开发中,调用第三方接口时,往往是提交数据,要异步去获取数据,下面这篇文章主要给大家介绍了关于springboot利用aop实现接口异步(进度条)的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-01-01
  • Java虚拟机处理异常的最佳方式

    Java虚拟机处理异常的最佳方式

    这篇文章主要给大家介绍了关于Java虚拟机处理异常的最佳方式,文中通过示例代码介绍的非常详细,对大家的学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-03-03
  • MyBatis-Plus实现连表查询的方法实例

    MyBatis-Plus实现连表查询的方法实例

    这篇文章主要给大家介绍了关于MyBatis-Plus实现连表查询的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-01-01
  • Java Stax解析XML示例

    Java Stax解析XML示例

    这篇文章主要介绍了Java Stax解析XML示例,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-09-09
  • 解决idea导入maven项目缺少jar包的问题方法

    解决idea导入maven项目缺少jar包的问题方法

    这篇文章主要介绍了解决idea导入maven项目缺少jar包的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Java中List排序的三种实现方法实例

    Java中List排序的三种实现方法实例

    其实Java针对数组和List的排序都有实现,对数组而言你可以直接使用Arrays.sort,对于List和Vector而言,你可以使用Collections.sort方法,下面这篇文章主要给大家介绍了关于Java中List排序的三种实现方法,需要的朋友可以参考下
    2021-12-12
  • 合并有序数组的实现(java与C语言)

    合并有序数组的实现(java与C语言)

    这篇文章主要介绍了合并有序数组的实现(java与C语言)的相关资料,这里对有序数组的合并分享了java版本和C语言版本的示例,需要的朋友可以参考下
    2017-08-08
  • java通过客户端访问服务器webservice的方法

    java通过客户端访问服务器webservice的方法

    这篇文章主要介绍了java通过客户端访问服务器webservice的方法,涉及java创建与调用webservice的相关技巧,需要的朋友可以参考下
    2016-08-08

最新评论