java有三大类加载器:
bootstrap
启动类加载器,也叫根加载器
主要加载 <java_home>/jre/lib/ 下的.jar文件或-Xbootclasspath参数指定的路径下的jar包。例如 rt.jar
只加载.jar文件中以 java,javax,sun开头的Class文件
启动类加载器是和JVM绑定的。是用C++实现的。
Extension
扩展类加载器
是在JVM外实现的,是由Orcale公司收购sun公司以后,实现的扩展。
主要加载<java_home>/jre/lib/ext 扩展包下的jar或者由系统变量-Djava.ext.dir指定位路径中的类库,
开发者直接可以使用扩展类加载器
system
系统类加载器
是在JVM外实现的,Java默认的加载器
它负责加载系统类路径java -classpath或-D java.class.path 指定路径下的类库
也就是我们常用到的classpath路径。
通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器。
Java 虚拟机对类是根据按需加载的方式,也就是说,当需要该类时,才会将Class文件加载到
方法区(JDK1.7)或元数据(JDK1.8)中生成java.lang.Class 类的一个class对象。在Java虚拟机中,这三种类加载器是以双亲委派模式来进行加载的。
双亲委派模式
双亲委派模式要求除了顶层的启动类加载器,其余的加载器都应当有自己的父类加载器。
但是双亲委派模式中的父子关系并不是通常所说的继承关系,而是相互组合来进行加载的。
ClassLoader 类的 loadClass方法:
步骤:
1、先检查方法区有没有加载过该类。
2、然后找该加载器有没有父类
3、如果没有父类,就用启动类加载器加载
4、如果启动类加载器查找<java_home>/jre/lib/ 下的jar包中有么有该类,如果没有,则加载不了
5、然后子加载器才会自己尝试着去加载。
如果开发人员编写了1个类:java.lang.LongTest
编译器是怎么加载的呢?
1、应用加载器委托扩展类加载器,扩展类加载器委托启动类加载器
2、启动类加载器寻找路径下没有该文件。则加载不了
3、扩展类加载器尝试着加载,去扩展包里查找该类,也没有。
4、应用类加载器尝试加载,去classpath下的路径下,找到该类,可以加载,但是会加载失败,因为java.lang是java的核心API包,是有访问权限的。不能随便改变Java的基本结构
双亲委派模式优点:
1、Java类随着加载器具有了一种优先级的层次关系
2、保证了一个Java类在方法区的Class对象只有1个
3、保证了Java的基本架构,核心包不能被随意替换,防止Java核心API库被随意篡改。(沙箱安全机制)