JVM 类加载器 基础知识

本文深入探讨JVM中的类加载机制,详细介绍了引导类加载器、扩展类加载器及应用类加载器的工作原理,并通过代码示例展示了如何确定特定类的加载器。此外,还分析了自定义类加载器的实现及其应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

概述:

1.引导类加载器:

2.扩展类加载器:

3.应用类加载器:

4.测试不同类使用的类加载器

5.自定义类加载器:


概述:

JVM规范中,类加载器分为两种:引导类加载器(C++实现),自定义类加载器(Java语言实现)

Note:可以使用JVM参数 -XX: +TraceClassLoading 参数去打印类的加载过程。

1.引导类加载器:

引导类加载器,除了加载java核心类,还负责加载扩展类加载器应用程序类加载器任何Java程序的运行都要做这些加载,即使这个java程序非常简单。

以下代码帮助我们了解引导类加载器:

package com.learn.classLoader;

import java.net.URL;
import java.util.Iterator;

import com.sun.net.ssl.internal.ssl.Provider;

public class BootStrapClassLoaderTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//*******ExtClassLoader与AppClassLoader都是在类sun.misc.Launcher内部定义的内部类
		System.out.println("*******启动类加载器********");
		//启动类加载器BootstrapClassLoader能够加载的API路径(java核心类 class文件)
		URL[] ruls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
		for (URL url : ruls) {
			System.out.println(url.toExternalForm());
		}
		
		//从上面的路径中随意选择一个类,jsse.jar包中的Provider.class,来看看它的类加载器是什么:引导类加载器
		ClassLoader classLoader = Provider.class.getClassLoader();
		System.out.println(classLoader);//null, 凡是想要得到BootstrapClassLoader,那么就会得到null
	}
}

执行结果:

扩展类加载器与应用类加载器也需要被加载,它们是由Launcher这个类去具体加载的。可以看到扩展类加载器实例化的时候没有传参,而应用类加载器在其构造函数中,传入扩展类加载器的引用,在其构造函数中,会将其赋值给“ClassLoader parent" 这个变量,做为其父加载器,所以parent变量就是一个引用,引用了父加载器,所以应用类加载器的父加载器是扩展类加载器,而扩展类加载器没有父加载器

 parent变量是在ClassLoader类中定义的,扩展类加载器与应用类加载器都间接继承了ClassLoader类。

2.扩展类加载器:

 以下代码帮助我们了解扩展类加载器:

package com.learn.classLoader;

import sun.security.util.CurveDB;

public class ExtClassLoaderTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//*******ExtClassLoader与AppClassLoader都是在类sun.misc.Launcher内部定义的内部类
		System.out.println("*******扩展类加载器********");
		//扩展类加载器能够加载的路径
		String extDirs = System.getProperty("java.ext.dirs");
		for (String path : extDirs.split(";") ) {
			System.out.println(path);
		}
		
		//C:\Program Files\Java\jre1.8.0_201\lib\ext目录下的sunec.jar为例,里面有个类CurveDB.class,以它为例,看看哪个加载器加载了它
		ClassLoader classLoader = CurveDB.class.getClassLoader();
		System.out.println(classLoader); //sun.misc.Launcher$ExtClassLoader@232204a1
	}

}

执行结果如下:

3.应用类加载器:

关于怎样获取应用类加载器,及其它相关知识,请参考"简单用户自定义类加载的实现":JVM-- 自定义类加载器,及执行结果分析_知难行难1985的博客-优快云博客

4.测试不同类使用的类加载器

特别注意数组类 的 类加载器

package com.learn.classLoader;

public class ClassLoaderTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//*******ExtClassLoader与AppClassLoader都是在类sun.misc.Launcher内部定义的内部类
		ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
		System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@73d16e93(地址)
		
		//获取其上层:扩展类加载器, 不是继承关系,而是类似于文件夹的层级
		ClassLoader extClassLoader = systemClassLoader.getParent();
		System.out.println(extClassLoader); //sun.misc.Launcher$ExtClassLoader@15db9742
		
		//获取其上层:引导类加载器,虽然是其父加载器(负责加载扩展和应用程序类加载器),但是获取不到,相互之间没有关系,引导类加载器是用C实现的
		ClassLoader bootstrapClassLoader = extClassLoader.getParent();
		System.out.println(bootstrapClassLoader); //null
		
		//用户自定义类的加载器:即用户自定义的类,是由哪个加载器加载的
		ClassLoader thisClassLoader = ClassLoaderTest.class.getClassLoader();
		System.out.println(thisClassLoader); //sun.misc.Launcher$AppClassLoader@73d16e93

		//String类的加载器
		//获取不到类加载器,为什么?因为String类是使用引导类加载器加载的,获取不到引导类加载器
		//******系统的核心类库(*******包括ExtClassLoader和AppClassLoader)都是使用引导类加载器进行加载的,
		//******出于安全考虑,BootStrap启动类加载器,只加载以java,javax,sun等开头的类。******
		ClassLoader stringClassLoader = String.class.getClassLoader();
		System.out.println(stringClassLoader);  //null
		
		try {
			//String类的加载器,获取的另一种方式
			ClassLoader classLoader = Class.forName("java.lang.String").getClassLoader();
			System.out.println(classLoader);  //null
			//自定义的类默认使用系统类加载器
			ClassLoader selfClassLoader = Class.forName("com.learn.classLoader.StringTest").getClassLoader();
			System.out.println(selfClassLoader);  //sun.misc.Launcher$AppClassLoader@73d16e93
			
			//关于数组类型的加载,使用的类加载器,与数组中元素使用的类加载器一致。
			String [] strArray = new String[10];
			System.out.println(strArray.getClass());
			System.out.println(strArray.getClass().getClassLoader());  //null,数组类的类加载器是引导类加载器,与数组中元素的类加载器是一样的。
			
			ClassLoaderTest [] classLoaderTestArr = new ClassLoaderTest[10];
			System.out.println(classLoaderTestArr.getClass().getClassLoader());  //null,数组类的类加载器是引导类加载器, 与数组中元素的类加载器是一样的。
			
			int [] intArr = new int[10];
			System.out.println(intArr.getClass().getClassLoader());  //null,特别注意,基本数据类型,是不需要进行加载的。
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

执行结果:

小结:

5.自定义类加载器:

特别注意其中的应用隔离,Spring, Tomcat中都有大量使用。

关于怎么实现自定义类加载器,请同样参考"简单用户自定义类加载的实现":JVM-- 自定义类加载器,及执行结果分析_知难行难1985的博客-优快云博客

参考尚硅谷 宋红康老师的教程

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值