当你写完了一个.java文件的时候,编译器会把他编译成一个由字节码组成的class文件,当程序运行时,JVM会首先寻找包含有main()方法的类,把这个class文件中的字节码数据读入进来,转化成JVM中运行时对应的Class对象。执行这个动作的,就叫类加载器。(运行时的前奏做类加载);
-
ClassLoader:是Java层几乎所有类加载器的父类,它定义了加载器的基本行为和加载动作
Bootstrap ClassLoader(启动类加载器)这个类加载器负责将一些核心的,被JVM识别的类加载进来,用C++实现,与JVM是一体的。
Extension ClassLoader(扩展类加载器)这个类加载器用来加载 Java 的扩展库
Applicaiton ClassLoader(本地类加载器)用于加载我们自己定义编写的类
User ClassLoader (用户自己实现的加载器)当实际需要自己掌控类加载过程时才会用到,一般没有用到。
注:在java中锁能够(synchronized)能够保证类文件完整加载进内存,不做详细分析。
双亲委托机制:
1.先检查需要加载的类是否已经被加载,如果没有被加载,则委托父加载器加载,父类继续检查,尝试请父类加载,这个过程是从下-------> 上;
2.如果走到顶层发现类没有被加载过,那么会从顶层开始往下逐层尝试加载,这个过程是从上 ------> 下;
注:用户自定义类加载器,不怎么用所以不做图解。
注意:事实上加载器之间不是通过继承,而是通过组合的方式来实现整个加载过程,即每个加载器都持有上层加载器的引用(不一定从本地类加载器优先,该图以用户自定义类而言)
那么问题来了,jvm是怎么判断类是否被重复加载呢?
-
JVM除了比较类是否相等还要比较加载这两个类的类加载器是否相等,只有同时满足条件,两个类才能被认定是相等的。
实际上,三层类加载器代表了JVM对于待加载类的三个信任层次,当需要加载一个全限定名为java.lang.Object的类时,JVM会首先信任顶层的引导类加载器,即优先用这个加载器尝试加载,如果不行,JVM会选择继续信任第二层的拓展类加载器,往下,如果三层都无法加载,JVM才会选择信任开发者自己定义的加载器。这种”父类“优先的加载次序有效的防止了恶意代码的加载。
作用:每一个类都只会被加载一次,避免了重复加载每一个类都会被尽可能的加载,维护Java类加载的安全(从引导类加载器往下,每个加载器都可能会根据优先次序尝试加载它)有效避免了某些恶意类的加载(比如自定义了Java.lang.Object类,一般而言在双亲委托机制下会加载系统的Object类而不是用户自定义的Object类)。
-
父加载器中加载的类对于所有子加载器可见
-
子类之间各自加载的类对于各自是不可间的(达到隔离效果)