详述Java类加载机制

类加载器分类

Java类加载器(Java Classloader)负责动态地将Java类加载到Java虚拟机的内存空间内, 是Java运行时环境(Java Runtime Environment)的一部分,JVM默认有3个类加载器,每个类加载器负责加载特定位置的Java类

三种类加载器

1、Bootstrap ClassLoader(引导类加载器)

概念
该类加载器通常由C++语言实现,不继承任何Java类,负责加载System.getProperty(“sun.boot.class.path”)所指定核心Java库,也可以通过java -Xbootclasspath指定其搜索路径;
加载路径证明:

public class Test {
	public static void main(String[] args) {
		System.out.println(System.getProperty("sun.boot.class.path"));
	}
}
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\resources.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\rt.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\sunrsasign.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\jce.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\classes

2、ExtClassLoader(扩展类加载器)

概念
该类加载器由sun.misc.Launcher$ExtClassLoader类实现,负责加载System.getProperty(“java.ext.dirs”)所指定的Java的扩展库,也可以通过java -Djava.ext.dirs指定其搜索路径,例如:java -Djava.ext.dirs=d:\classes HelloWorld;注意:如果将自己开发的 jar 文件放在System.getProperty(“java.ext.dirs”)所指定的目录中,也会被 ExtClassLoader类加载器加载;
加载路径证明:

public class Test {
	public static void main(String[] args) {
		System.out.println(System.getProperty("java.ext.dirs"));
	}
}
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext;
C:\windows\Sun\Java\lib\ext

3、AppClassLoader(系统类加载器)

概念
该类加载器由sun.misc.Launcher$AppClassLoader类实现,负责加载System.getProperty(“java.class.path”)或CLASSPATH环境变量所指定的Java类,也可以加上-cp来覆盖原有的classpath设置,例如: java -cp ./classes HelloWorld;说明:默认情况下自定义类都由该类加载器加载。
加载路径证明:

public class Test {
	public static void main(String[] args) {
		System.out.println(System.getProperty("java.class.path"));
	}
}
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\resources.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\rt.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\jce.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-32.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;
D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;
D:\workspace\mybatis\bin;
D:\workspace\mybatis\lib\mybatis-3.4.4.jar;
D:\workspace\mybatis\lib\mysql-connector-java-5.1.9.jar

4、三种类加载器的关系:

Java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,如下图所示:

如下代码证明上图所列关系:

public class Test {
public static void main(String[] args) {
		ClassLoader classLoader=Test.class.getClassLoader();//得到自定义类的类加载器。说明自定义类由ADDCL加载。
		System.out.println(classLoader.getClass().getName());
		classLoader=classLoader.getParent();//得到上一级类加载器。
		System.out.println(classLoader.getClass().getName());
		classLoader=classLoader.getParent();//得到上一级类加载器。
		System.out.println(classLoader);
	}
}

输出如下结果:
在这里插入图片描述
上边第二次调用方法时输出null,是因为顶层类加载器不是由java代码写的,用下边的代码证明:

public class Test {
	public static void main(String[] args) {
		ClassLoader classLoader=Test.class.getClassLoader();//得到自定义类的类加载器。说明自定义类由ADDCL加载。
		classLoader=classLoader.getParent();//得到上一级类加载器。
		classLoader=classLoader.getParent();//得到上一级类加载器。
		System.out.println(classLoader.getClass().getName());
	}
}

输出结果如下:
在这里插入图片描述
类加载器实例化过程:
通过java命令执行Java程序时,首先初始化JVM,产生Bootstrap ClassLoader(启动类加载器)——>Bootstrap ClassLoader自动加载Extended ClassLoader(扩展类加载器),并将其父ClassLoader设为Bootstrap Loader——>Bootstrap ClassLoader自动加载AppClass ClassLoader(系统类加载器),并将其父ClassLoader设为Extended ClassLoader。

类加载器运行原理

双亲委派机制
一个类加载器接到加载某个类的任务时,不会自己去尝试加载这个类,而是先将加载任务委托给父类加载器去完成, 每一个层次的类加载器都是如此,因此加载任务最终传递到最顶层的启动类加载器,然后自上而下从最顶层类加载器开始,每级类加载器在其搜索范围内尝试完成加载任务,如果某级类加载器完成类加载任务,就成功返回,类加载结束,否则交给下级类加载器尝试完成加载任务,以此类推,当所有父类加载器都无法完成类加载任务时就会回退到最初的类装载器时,如果该加载器也不能完成类的装载,则抛出ClassNotFoundException异常,这种加载类的机制称为双亲委派机制。
证明:
创建一个Student类,如下
在这里插入图片描述
1,将student.java打成var包,放到(D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext)路径中,顶层会加载,顶层加载之后,自定义的不会再加载了。
如下代码:

public class Test {
	public static void main(String[] args) {
		ClassLoader classLoader=Student.class.getClassLoader();//将student.java打成var包,放到(D:\Program_Files\Java\jdk1.8.0_131\jre\lib\ext)路径中,顶层会加载,顶层加载之后,自定义的不会再加载了。
		System.out.println(classLoader.getClass().getName());
	}
}

在这里插入图片描述
2,将student.java打成var包,放到自定义的D:\Program_Files\Java\jdk1.8.0_131\jre\classes中

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

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值