从Java虚拟机的角度来说,类加载器有两种,一种是启动类加载器, 即Bootstrap ClassLoader(启动类加载器),这个类加载器用C++ 语言实现,是虚拟机的一部分,另外一种类加载器是ExtClassLoader加载器(扩展类加载器),AppClassLoader(系统类加载器),这两个类加载器是用java 语言实现的独立于虚拟机的外部,并且全部继承自ClassLoader类。启动类加载器用来加载JAVA_HOME/lib目录下的类或者是-Xbootclasspath参数中指定的类,并且使虚拟机识别的类库加载到虚拟机内存的。扩展类加载器负责加载JAVA_HOME\jre\lib\ext 目录下或者被java.ext.dirs 系统变量所指定的路径下的所有类库。系统类加载器负责加载用户路径上所指定的类库,用户自定义的类基本都由这个类来加载。再来说一下这三个类加载器的关系,系统类加载器的父加载器是扩展类加载器,而扩展类加载器的父加载器是null ,并不是启动类加载器,注意系统类加载器和扩展类加载器并不是继承的关系。再来解释一个概念,双亲委派机制,这个意思是说在加载一个类的时候,会优先交给父加载器去加载,当父加载器是null的时候 ,则会让启动类加载器去加载 ,当父加载器加载或者启动类加载器都加载不了的话,才会由当前类加载器来加载,来看一下双亲委派机制的具体实现代码。
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
long t1 = System.nanoTime();
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
这段代码是双亲委派机制实现的具体代码,首先是findLoadedClass方法,
这个方法是用来查找该类是否有被加载,如果加载过则直接返回该类的Class 对象,
若没有加载则会执行 parent.loadClass 方法,这个是表示让当前类的父类加载器去加载该类,
当父类加载器为null ,则会执行findBootstrapClassOrNull方法,这个方法是意思是用启动类加载器去加载当前类,
当父类加载器或者启动类加载器无法加载该类的时候,则会由当前类加载器去加载该类。
用户自定义的类一般是由系统类加载器去加载,当加载一个类的类加载器显示为null 的时候,
那么这个类便是由启动类加载器去加载的。