类加载器
简介
类加载器(ClassLoader)它负责加载class文件,class文件在文件开头有特定表示,并且ClassLoader只负责class文件的加载,至于是否可以运行,则由Execution Engine决定.。
例如以下案例,我们的Car.class文件被类加载器导入到jvm虚拟机中,然后加载并初始化后形成一个car的模板,我们通过这个模板进行实例化。
启动器分类
-
启动类加载器(Bootstrap)
主要负责加载jre中的最为基础、最为重要的类。例如$JAVA_HOME/jre/lib/rt.jar
等等,以及由虚拟机参数-Xbootclasspath
指定的类。由于它由c++代码实现,没有对应的java对象,因此在java中,尝试获取此类时,只能使用null来指代。 -
扩张类加载器(Extension)
由java代码实现,用于加载相对次要,但又通用的类比如存放在 JRE 的 lib/ext 目录下 jar 包中的类,以及由系统变量 java.ext.dirs 指定的类。如$JAVA_HOME/jre/lib/ext/*.jar
。 -
应用程序类加载器(AppClassLoader)
由Java代码实现, 它负责加载应用程序路径下的类(也就是我们自己写的类)。(这里的应用程序路径,便是指虚拟机参数-cp/-classpath
、系统变量java.class.path
或环境变量CLASSPATH
所指定的路径。)默认情况下,应用程序中包含的类便是由应用类加载器加载的。
这里要注意的是它在加载的时候会用到一个叫双亲委派机制
的技术,主要是为了防止类被confuse加载和防止篡改jdk中的类(包名类名一致时)。 -
用户自定义的加载器:Java.lang.ClassLoader的子类,用户可以定制类的加载方式。例如可以对 class 文件进行加密,加载时再利用自定义的类加载器对其解密。
除了BootStrap Class Loader,其他的类加载器,都是Java.lang.ClassLoader的子类。其他的类加载器都由sum.misc.Launcher类加载后得到。
双亲委派机制
双亲委派模型
每当一个类加载器接收到加载请求时,它会先将请求转发给父类加载器。在父类加载器没有找到所请求的类的情况下,该类加载器才会尝试去加载。
优势
- 这采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。
- 其次是考虑到安全因素,防止java核心api中定义类型不会被用户恶意替换和篡改,从而引发错误。