Java反射之二——类加载器ClassLoader

Java程序在编写完成之后,为了能够运行,首先会被编译为class文件。然后,在Java程序的运行过程当中,每当需要一个新的类,就需要将其对应的class文件加载到JVM虚拟机当中。加载class文件的叫作ClassLoader。

JDK具有多个层次的ClassLoader,最根上的那个叫作BootStrap ClassLoader,负责加载JDK中最核心的类。BootStrap ClassLoader不是由Java语言编写的,一般是由本地语言,比如汇编语言,C/C++等语言编写的,所以严格意义上来讲它不是一个Java类,也没有对应的名字。而其他的ClassLoader都是由Java语言编写的,本质上都是一个Java类,所以,这些ClassLoader(除了BootStrap ClassLoader)作为一个Java类文件也需要相应的更高层次的ClassLoader将他们本身Load到内存当中。(所以事实上是JVM首先利用BootStrap ClassLoader将核心类加载进来,其中就包括了一些其他的ClassLoader类,然后这些被BootStrap ClassLoader加载进来的ClassLoader类再去将其他的类加载进来)

除了BootStrap ClassLoader之外,第二个层次的ClassLoader是extesion ClassLoader,负责加载jre/lib/ext里面的类。

第三个层次的是application ClassLoader,负载加载用户自己编写、定义的类。除此之外,还有其他的ClassLoader。

下面看例程:

public class TestClassLoader {

	public static void main(String[] args) {
		System.out.println(String.class.getClassLoader());
		System.out.println(TestClassLoader.class.getClassLoader().getClass().getName());
	}
}

程序运行结果如下,因为String类作为JDK的核心类,由BootStrap ClassLoader加载,而BootStrap ClassLoader并非由Java语言编写,严格上来说并不是一个Java类,所以String.class.getClassLoader()的值为null。而用户自己定义的类的ClassLoader可以看出来是APPClassLoader。

null
sun.misc.Launcher$AppClassLoader

再看一个例程:

public class TestClassLoader {
	public static void main(String[] args) {
		ClassLoader c = TestClassLoader.class.getClassLoader();
		while(c != null) {
			System.out.println(c.getClass().getName());
			c = c.getParent();
		}
	}
}

程序的运行结果为:

sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader

这说明了每一个ClassLoader都有一个引用(parent)指向比他更高层次的ClassLoader。也就是说JDK中ClassLoader具有如下图所示的的层次,尤其需要注意的是,图中的关系不是继承关系。(而是每一个低层次的ClassLoader都有一个引用(parent)指向比他更高层次的ClassLoader。)

Java反射之二——类加载器ClassLoader_第1张图片

这样做的用处是什么呢?答案就是为了实现双亲委派加载机制:当一个类需要加载的时候,对应的ClassLoader首先会递归的问一下它的parent所指向的ClassLoader是否已经加载过这个类,如果已经加载过,那么这个类就不会被再次加载。,如果没有被加载过,才会加载这个类。

这种机制的好处是什么呢?安全!这样一来,用户如果自己定义一些具有恶意代码的核心类如重写java.lang.String,就不会被加载到JVM中。因为为了加载这个用户自定义的类,会从APPClassLoader询问到ExtClassLoader再询问到BootStrap ClassLoader,而此时BootStrap ClassLoader已经加载过真正的java.lang.String了,就会告诉下面的CLassLoader说这个类你们不用加载了,我已经加载过了(加载的是正确的String)。

 

你可能感兴趣的:(Java基础之反射)