当程序在运行时,会调用一个入口函数来调用系统的相关功能,这些功能都包含在不同的class里面,有时候需要从一个class去调用其他class的方法,如果另外一个文件不存在的,则会引发系统异常。而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,只有class文件被载入到了内存之后,才能被其它class所引用。classLoad就是来用来加载class的。
java默认有三种classLoader
1. Bootstrp loader
Bootstrp加载器是用C++语言写的,它是在Java虚拟机启动后初始化的,它主要负责加载%JAVA_HOME%/jre/lib,-Xbootclasspath参数指定的路径以及%JAVA_HOME%/jre/classes中的类。
也是所有的calssLoader的parent。
2.Extension ClassLoader
称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。
3.App ClassLoader
称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。
加载机制
在Java虚拟机启动后初始化的,将会对Bootstrp loader进行初始化,然后Bootstrp loader加载Extension ClassLoader,最后再由Extension ClassLoader加载App ClassLoader,层层下来,形成了父子的关系。
当加载类时候,将会在当前层级判断类是否已经存在,如果存在则返回类的实例,如果不存在,则在父类中寻找,直到到达Bootstrp loader为止。
贴上loadClass的代码
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
{
try {
if (parent != null) { //如果父类不为空委托父类加载
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);//如果没有父类加载器,则委托bootstrap加载器加载 }
} catch (ClassNotFoundException e) {
c = findClass(name);//如果父类加载没有加载到,则通过findClass来加载。 }
}
if (resolve)
{
resolveClass(c);
}
return c;
}
}
看到这里不禁要问,为什么要用这种方式来加载,当我们自定义classLoader时候不会触及Bootstrp loader,也就保证了Bootstrp loader中的类保持自己的样子,如果我们写一个String类,他会父类中发现了该类过后返回,也就保证了一直使用的是系统的String,不会被其他的恶意破坏。