2021-05-05
在 Java 中,所有的程序都是通过 "*.class" 字节码的文件进行存储的,这样在 JDK 执行类的时候每个类都会存在一个相应的类加载器;如果想获得这些类加载器,直接依据 Class 类即可,在 Class 类中提供如下一个重要方法:
public ClassLoader getClassLoader()
由于在 JVM 中所需要进行加载的类比较多,所以对于 ClassLoader 来讲为了安全的设计起见,往往会存在由若干个父 ClassLoader ,如果要想获得这些 ClassLoader 的信息,则可以利用 ClassLoader 类中提供的如下方法来完成:
public final ClassLoader getParent()
如果按照递归的处理形式来讲,可以持续使用如上的方式来获得程序里面所使用的全部的类加载器的信息。
观察 String 类的 ClassLoader
public class StringClassLoader {
public static void main(String[] args) {
String message = "JadeBamboo";
System.out.println(message.getClass().getClassLoader());
}
}
输出:
null
虽然此时通过代码执行后发现,String 类的 ClassLoader 是一个 null,主要的原因是这个 null 是由 JVM 来实现的类加载器,我们的程序时无法得到这个类加载器的。
观察自定义类的类加载器
class Book {}
public class SelfClassLoader {
public static void main(String[] args) {
Class<?> cla = Book.class;
System.out.println(cla.getClassLoader());
System.out.println(cla.getClassLoader().getParent());
System.out.println(cla.getClassLoader().getParent().getParent()); // Bootstrap
}
}
输出:
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@677327b6
null
现在的 ClassLoader 一共有如下几个:
Bootstrap:此为 JVM 系统内部所提供的类加载器的处理机制,JVM 原生提供的类加载机制,专门用于加载系统类;
-
PlatformClassLoader:平台类的加载器,在JDK 1.8 及以前的版本里面为 "ExtClassLoader";
在JDK 1.8 及以前的所有 JDK 里面为了方便进行第三方程序组件的扩展,会提供一个专属的 ext 目录(
D:\Software\Java\JDK\jre\lib\ext
)。 AppClassLoader:应用程序类加载器,用户自己定义类的加载器
之所以在 Java 设计范畴里面为 JVM 设计不同层次的类加载器,主要的原因在于要实现"双亲加载"。为了提供类加载器的安全级别,在 Java 中对于所有的系统类使用系统类的加载器,如果是用户自定义的类使用自定义类的加载器,这样的目的时为了防止类重名的时候所造成的困扰,例如,现在某个恶意的用户定义了一个 "java.lang.String" 类,如果这个类里面存在许多恶意的程序代码,那么在用户不知情的情况下使用了这个类,并且加载了恶意代码就会导致程序的安全性的问题,那么为了解决这一点,才使用不同的加载器。用户自定义的 String 类和系统中的 String 类所进行加载的时候采用的加载器是有区别的,所以才能够保证程序类的加载正确,所谓的双亲就是防止恶意程序与系统类重名所造成的恶意加载。