类加载器
首先应该明确jvm有公开的标准,并且有很多实现版本,最为常用的就是HotSpot版(这个版本的jvm是由c++语言进行实现)。
其次jvm的作用:JVM中类加载器的作用就是:加载class字节码文件,加载并初始化Class。
过程如图所示:(简略图)
java中类加载器有4种:由高到低的排序
1.虚拟机自带的加载器
2.启动类(根)加载器 (位于jdk的lib中的 rt.jar)
3.扩展类加载器(位于jre/lib/ext目录下)
4.应用程序(系统类)加载器
它们的执行顺序是4321,由高到低(1234)是父子类关系。
当明确过这些概念后就可以了解双亲委派机制。
public class Student {
public static void main(String[] args) {
Student s1 = new Student();
Class<? extends Student> aClass1 = s1.getClass();
ClassLoader classLoader = aClass1.getClassLoader();
System.out.println(classLoader);
//输出结果AppClassLoader
System.out.println(classLoader.getParent());
//输出结果ExtClassLoader 扩展类加载器 jre/lib/ext
System.out.println(classLoader.getParent().getParent());
//输出结果 null 可能造成的原因1.不存在 2.java程序获取不到 rt.jar
//而null是因为 jvm是由c++写的,能够获取到,但是无法调用
}
}
双亲委派机制
1.当类加载器需要加载初始类(即收到加载类的请求时),并不会立即执行,而是调用父类的类加载器去执行,当父类类加载器还存在父类时,则再由父类的上层类加载器执行,最终到达启动类加载器进行执行。AppClassLoader—>ExtClassLoader—>Bootstrap ClassLoder
2.如果在启动类加载器执行时,能够加载到该类,则由启动器加载类进行加载。
3.如果父类加载器无法加载这个类,就抛出异常,调用子类加载器,进行加载,依次往下执行,直到某各类加载器能够完成加载。Bootstrap ClassLoder—>ExtClassLoader—>AppClassLoader
简单地说就是:子类给父类,父类加载器能加载就优先加载,不能则父类再给子类类加载器。
这种机制首先能够避免重复加载,其次能够保护java的核心api不被破坏。
举个例子:
大家有没有想过写一个和SreingAPI同名的类,即创建java.lang.String类,同时定义一个toString方法,那么在String类中的main方法执行入口中去执行这个String 对象的toString方法,结果会如何呢?
package java.lang; //创建和系统StringAPI,同类名的String类
public class String {
public String toString(){
return "hello";
}
public static void main(String[] args) {
String s = new String();
System.out.println(s);
}
}`.
结果当然会报错:错误信息如图所示
原因就是:类加载器一层一层向上找,最终使用启动类加载器,而启动类加载器位于jdk的rt.jar,在这里加载到的类时java的核心api:String.那么就不会执行自己定义的String类,而在核心API中并没有main方法,因此保存会找不到。