类加载器
-
什么是类加载器?
类加载器是一个用来加载类文件的类。java源码通过javac(java语言编程编译器)编译成.class文件后,JVM来执行文件中的字节码来执行程序。
类加载器负责加载文件系统、网络或其它的类文件。
-
类加载有哪几种?
三种默认的类加载器:
BootStrap类加载器
Extension类加载器
Application类加载器
-
默认类加载器的职责
- Bootstrap
Bootstrap类加载器负责加载rt.jar中的JDK类文件,它是所有类加载器的父加载器。Bootstrap类加载器没有任何父类加载器,如果你调用String.class.getClassLoader(),会返回null,任何基于此的代码会抛出NullPointerException异常。Bootstrap加载器被称为初始类加载器。
- Extension
Extension将加载类的请求先委托给它的父加载器,也就是Bootstrap,如果没有成功加载的话,再从jre/lib/ext目录下或者java.ext.dirs系统属性定义的目录下加载类。Extension加载器由sun.misc.Launcher$ExtClassLoader实现。
- Application
Application类加载器负责从classpath环境变量中加载某些应用相关的类,classpath环境变量通常由-classpath或-cp命令行选项来定义,或者是JAR中的Manifest的classpath属性。Application类加载器是Extension类加载器的子加载器。通过sun.misc.Launcher$AppClassLoader实现。
-
类加载机制
全盘负责:所谓全盘负责,就是当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。
双亲委派:所谓的双亲委派,则是先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父加载器,依次递归,如果父加载器可以完成类加载任务,就成功返回;只有父加载器无法完成此加载任务时,才自己去加载。
缓存机制。缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。
JVM加载class文件的原理
-
原理
Java中的所有类,都需要由类加载器装载到JVM中才能运行。Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。很显然,这样做的目的可以节省内存,提高效率。
在JVM加载的class文件的过程中,类加载器主要负责.class文件从硬盘读到内存中, 类加载器,它负责把class文件从硬盘读取到内存中。在开发过程中,我们几乎不需要关心类的怎样加载,这些方法都在底层封装好了,但像我们学过的反射,就需要显式的加载所需要的类。
其中类加载器装载是指定装载器,而反射中的class.Forname是使用当前类加载器装载
反射中类加载器代码
public class Demo01_获取类的字节码对象 { public static void main(String[] args) throws ClassNotFoundException { /*Person p = new Person("zhangsan", 23); Class c1 = p.getClass(); Class c2 = Person.class; System.out.println(c1 == c2);*/ String className = new Scanner(System.in).nextLine(); Class c3 = Class.forName(className); System.out.println(c1 == c3); } }