类加载器加载的目录
获取启动类加载器加载的目录 System.getProperty("sun.boot.class.path");
获取扩展类加载器加载的目录 System.getProperty("java.ext.dirs");
获取应用类加载器加载的目录 System.getProperty("java.class.path");
将test.Test2.class移到启动类加载器加载的目录,然后其加载类
启动类加载器加载目录如下
通过上述案列可以分析出,test.Test2是由启动类加载器加载的,验证了双亲委派优先父加载器加载
扩展类加载器加载案列
通过上述案列得出AESKeyGenerator是由扩展类加载器加载的,手动修改扩展类加载器加载的目录,修改完成后在修改后的目录是找不到AESKeyGenerator,所以会报错
java -Djava.ext.dirs=./ test.Test19
将本地目录作为扩展类加载器加载的目录
类加载器命名空间定义以及举例
同一个命名空间内的类时相互可见的
子加载器的命名空间包含所有的父加载器的命名空间。因此由子加载器加载的类可以看见父加载器加载的类。例如系统类加载器加载的类能看见跟类加载器加载的类。
由父加载器加载的类不能看见子加载器加载的类。
如果两个加载器之间没有直接或者间接的父子关系,那么它们各自加载的类相互不可见
上述案列是因为classLoader1与classLoader2的父加载器都为AppClassLoader,所以classLoader1加载完Person后在内存的缓存中是有Person.class的,classLoader2委托AppClassLoader加载的时候直接就从内存中获取Person.class,所以他们是一致的,method方法也是可以执行的
当删除当前classpath下的Person.class文件,将Person.class文件移到D盘下
此时当前的classPath下没有Person.class文件,会分别由classLoader1加载器与classLoader2加载器加载,会存在classLoader1加载器的命名空间以及classLoader2加载器的命名空间,根据 如果两个加载器之间没有直接或者间接的父子关系,那么它们各自加载的类相互不可见 的规则那么classLoader1与classLoader2加载的类时相互不可见的也是不相同的,这里会有很有趣的问题 java.lang.ClassCastException: test.Person cannot be cast to test.Person
修改扩展类加载器加载路劲案列
修改扩展类加载路劲为当前路径
执行 java -Djava.ext.dirs=./ test.Test22
可以发现还是使用AppClassLoader加载的Test22以及Test1
扩展类加载器不能直接加载.class文件,需要将.class文件打成jar包
jar cvf test.jar test/Test1.class
再次执行 ,可以发现Test1是通过扩展类加载器加载的,因为此处只将Test1打成jar包了
类加载器双亲委派模式的好处
1. 可以确保java核心库的类型安全: 例如所有的JAVA应用都至少会引用java.lang.Object类,也就是说在jvm的运行期间,java.lang.Object类会被加载到java虚拟机中,如果这个过程是由自己定义的java类加载器完成的,那么很有可能在jvm中存在多个版本的java.lang.Object类,也就是说在jvm的运行期间而这些类之间是相互不兼容的(命名空间不同导致的)。
借助双亲委派机制,java核心类库的加载必须由启动类加载器加载,从而确保java中使用的核心类库的版本统一,他们之间是相互兼容的
2. 可以保证java核心类库加载的类不会被自定义类所替代。
3. 不同类的加载器可以为相同名称的类(binary name)创建额外的命名空间。相同名称的类可以并存与不同命名空间的内存中,不同类加载器加载的类之间是相互不兼容的就相当于在java虚拟机内部创建了一个又一个相互独立并且隔离的的java空间,这类技术在很多框架都得到了使用。
启动类加载器相关及案列
在运行期间,一个Java类是由该类的完全限定名(binary name,二进制名)和用于加载该类的定义类加载器(defining loader)所共同决定的。如果同样名字(即相同的限定名)的类是由两个不同的加载类所加载,那么这些类就是不同的,即便.class文件的字节码完全一样,并且从相同的位置加载也是如此。
在Oracle的Hotspot实现中,系统属性 sun.boot.class.path如果被修改错了,则运行会出错,提示如下错误信息:
Error occureed during initialization of VM
java/lang/NoClassDefFoundError: java/lang/Object
内建于JVM中的启动类加载器会加载java.lang.ClassLoader以及其他的java平台类,当JVM启动时,一块特殊的机器码会运行,它会加载扩展类加载器以及系统类加载器,这块特殊的机器码叫做启动类加载器(BootStrap)。启动类加载器并不是java类,而其他的加载器都是java类,启动类加载器是特定于平台的机器指令,它负责开启整个加载过程
所有类加载器(除了启动类加载器)都被实现为Java类。不过总归要有一个组件来加载第一个java类加载器,从而让整个加载过程能够顺利进行,加载第一个纯JAVA类加载器就是启动类加载器的职责。
启动类加载器还会负责加载JRE正常运行时所需的基本组件,这包括java.util与java.lang包中的类等等
java -Djava.system.class.loader=test.Test16 test.Test23
网友评论