类加载器
双亲委派模型
使用双亲委派模型的好处
- 安全性,避免用户自己编写的类动态替换Java的一些核心类。如果不采用双亲委派模型的加载方式进行类的加载工作,那我们就可以随时使用自定义的类来动态替代Java核心API中定义的类。例如:如果黑客将“病毒代码”植入到自定义的String类当中,随后类加载器将自定义的String类加载到JVM上,那么此时就会对JVM产生意想不到“病毒攻击”。而双亲委派的这种加载方式就可以避免这种情况,因为String类已经在启动时就被引导类加载器进行了加载。
- 避免类的重复加载,因为JVM判定两个类是否是同一个类,不仅仅根据类名是否相同进行判定,还需要判断加载该类的类加载器是否是同一个类加载器,相同的class文件被不同的类加载器加载得到的结果就是两个不同的类。
- Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存在在rt.jar中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的Bootstrap ClassLoader进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,那系统中将会出现多个不同的Object类,程序将混乱。因此,如果开发者尝试编写一个与rt.jar类库中重名的Java类,可以正常编译,但是永远无法被加载运行。
我们了来了解一下这些方法:
- loadClass()方法:负责以双亲委托方式去加载类
- findClaa()方法:就根据类的包路径找到class文件
- defineClass()方法:负责从class字节码中加载class对象
我们来看一下loadClass()方法的源码
由源码可知,findClass 使用次数小于等于 loadClass 使用次数。
loadClass()方法是实现双亲委派模型的关键
class TestDemo {
private int data;
}
public class Test3 {
public static void main(String[] args) {
System.out.println(String.class.getClassLoader());
System.out.println(TestDemo.class.getClassLoader());
}
}
实现类加载器时不能破坏双亲委派模型,需要重写一个findClass()方法