类加载器
Java中的类,想要运行就必须把类对应的class文件加载到内存,JVM中真正负责加载class文件内容的是类加载器
javaSE-API中,有一个类:java.lang.ClassLoader
,他就是JVM中的类加载器
JVM启动后,默认会有的四种类加载器:
-
启动类加载器(bootstrapClassLoader,非java语言实现,c++实现的)
作用:加载指定路径中jar里面的class文件
路径1:C:\Program Files\Java\jdk1.8.0_74\jre\lib\
路径2:C:\Program Files\Java\jdk1.8.0_74\jre\classes\
( 如果有这个目录的话)
例如:rt.jar -
拓展类加载器(ExtClassLoader,Java语言实现,是ClassLoader类型的对象)
作用:加载指定路径中jar里面的class文件(只能是jar中存在的class)
路径:C:\Program Files\Java\jdk1.8.0_74\jre\lib\ext\
例如:ext中默认存在的jar,或者用户放到ext目录下的jar包 -
应用类加载器(AppClassLoader,Java语言实现,是ClassLoader类型的对象)
作用:加载指定路径中class文件或者jar里面的class文件
路径:CLASSPATH中配置路径,这个是用户自己配置的
例如:.:bin:hello.jar
-
自定义类加载器:开发人员自己写的
我们最常使用的就是应用类加载器,因为它可以通过CLASSPATH中的路径,去加载程序员自己编写的class文件到内存中
我们也可以把自己最常用的jar包(注意这里是jar包不是单个class文件哦),放到ext目录中,让拓展类加载器去自动加载这个jar中的class文件到内存,这样我们的代码就可以直接使用到这个jar中的类了(这个方法可以使用但是不推荐)
但是,大多数情况下,即使我们需要用到其他jar中的代码,也一般会把jar中所有的路径配置到CLASSPATH中,让应用类加载器进行加载,这样会更加方便统一管理项目中使用的所有的jar
关于启动类加载器,他不是Java语言编写的,我们一般不要去动它的路径或者jar,他是负责在JVM启动的时候,吧JRE环境中最重要的一些library加载到内存,一旦出问题,JVM就无法正常运行
双亲委托机制
JDK默认的类加载机制,并非强制。(可以修改)
多个类加载器之间共同协作,然后把需要使用或运行的类加载到内存去执行,他们直接共同合作的方式就是双亲委托机制。
例:java com.test.demo.Hello
命令
- 当前要加载Hello.class文件中的类
- 首先加载任务交给应用类加载器
- 然后应用类加载器把任务委托给自己的父加载器(拓展类加载器)
- 拓展类加载器把任务委托给自己的父加载器(启动类加载器)
- 启动类加载器尝试去加载这个类,但是在指定路径下并没有找到
- 然后任务有交回给拓展类加载器,拓展类加载器尝试加载这个类,但是在指定路径中没找到
- 任务又交回给应用类加载器
- 最后应用类加载器从CLASSPATH中指定的路径里面找到并加载了这个类,完成类加载的过程
思考:JavaSE-API中已经提供了一个类java.lang.System的类,如果我们也编写一个类加做System,同时指定它在java.lang包下面,那么这个时候我们是否能使用自己编写的java.lang.System类来代替JavaSE-API中的java.lang.System类?
不可以。因为当加载自己编写的java.lang.System的时候,内存中已经加载了jdk自带的java.lang.System(rt.jar),自己写的就不会再被加载
自己开发的class文件能不能被启动类加载器加载?
可以。
但并不是将jar直接丢进jdk/jre/lib
下,而是在运行java程序的时候需要手动指定
Xbootclasspath/a:jar包路径
这样就可以通过启动类加载器去加载自己开发的类