1.类加载器
1.BootStrapClassLoader 启动类加载器。加载rt.jar 以及 java. 开头的类。
2.ExtClassLoader 扩展类加载器。 Extent。加载 javax. 开头的类。
3.AppClassLoader 应用程序类加载器。加载 class文件下的类。
4.自定义加载器。
2.双亲委派模型
先判断该类的父加载器能否加载该类,若父类加载器能加载则交给父类加载器来加载,若父类无法加载,则自己加载。如果自己也不行,则抛ClassNotFoundException。双亲委派模型确保了内存中只有一份相同的字节码。不会重复加载多次。
每个class在加载的时候,会先判断缓存中是否已经加载过了该类,如果已经加载了,则直接从缓存中取。如果缓存中没有,jvm再到文件中取出二进制数据,转换成class加载到内存中。这也是为什么修改了class文件不起效果,需要重启jvm才可以。
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) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
AppClassLoader 加载classpath下的class。classpath主要包括两部分:一部分是 WEB-INF下的classes,一部分是WEB-INF下的lib。AppClassLoader继承UrlClassLoader,按照文件顺序来加载。所以一般先加载classes,在加载lib中的jar包。当发现有jar错误想调试时,可以在classes中创建一个相同包名类名的class,这样类加载器会加载这个类而不会加载jar包中的类。