简介

介绍类加载器的分类和特性

类加载器

java 加 java加载器有哪些_类加载器

加载器类型

如上图所示,类加载器大致可分为四大类,如上他们是有父子关系的,启动类加载器最先开始(用C++写的),后面加载上子加载器

1.启动类加载器

2.扩展类加载器

3.应用类加载器

4.自定义类加载器

在Java9之前,大致类加载器功能如下:

启动类加载器:负责加载最为基础的类、最为重要的类,比如存放在JRE的lib目录下的jar包中的类(以及由虚拟机参数 -Xbootclasspath 指定的类)

扩展类加载器:负责加载相对次要、但又通用的类,比如存放在JRE的lib/ext目录的jar包重点类(以及由系统变量java.ext.dirs指定的类)

应用类加载器:负责加载应用程序路径下的类(应用程序路径指虚拟机参数 -cp/-classpath、系统变量 java.class.path 或环境变量 CLASSPATH所指定的路径)

自定义类加载器:负责加载自定义的特殊的类。比如对class文件进行加密后,利用自定义的类加载器进行解密加载。

自定义加载器还有一个骚操作,功能描述大致如下:

在 Java 虚拟机中,类的唯一性是由类加载器实例以及类的全名一同确定的。即便是同一串字节流,经由不同的类加载器加载,也会得到两个不同的类。在大型应用中,我们往往借助这一特性,来运行同一个类的不同版本。

双亲委托机制

类加载器有个非常重要的机制:双亲委托机制

当类加载器要加载一个类时,如果自己曾经没有加载过这个类,则层层向上委托给父加载器尝试加载。如果父加载器都没有,才自己进行加载

为什么需要双亲委托机制呢:因为用它可以保证类的唯一性

添加引用类的几种方式

通过的前面的介绍,我们可以得到下面几种引用类的添加方式

1.放到JDK的 lib/ext 下,或者 -Djava.ext.dirs

2.java -cp/classpath 或者 class 文件放到当前目录

3.自定义 ClassLoader 加载

4.拿到当前执行类的 ClassLoader,反射调用 addURL 方法添加 Jar 或者 路径(JDK9无效)

自定义加载器的一些玩法

加载两个同名类

虽然双亲委托机制保证了类的唯一性,但是只是父子关系才行,如果是兄弟关系,那就可以加载同一个类

在前面说过,类的唯一性是由类加载器+类名进行确定的,如同下面的代码,虽然都是同一个类,但通过不同的类加载器进行加载,被视为不同的类

import java.lang.reflect.Method;
public class Test{
public static void main(String[] args){
CustomClassLoader classLoader1 = new CustomClassLoader("/Users/yu/Desktop/lib");
CustomClassLoader classLoader2 = new CustomClassLoader("/Users/yu/Desktop/lib");
try {
Class c1 = classLoader1.findClass("Person");
Object instance1 = c1.newInstance();
Class c2 = classLoader2.findClass("Person");
Object instance2 = c2.newInstance();
Method method = c1.getDeclaredMethod("setPerson", Object.class);
method.invoke(instance1, instance2);
} catch (Exception e) {
e.printStackTrace();
}
}
}