类加载器命名空间实战剖析与透彻理解

基于上一次【https://www.cnblogs.com/webor2006/p/9129149.html】的程序进一步进行修改:

编译运行:

此时咱们在设置的桌面路径中将MySample.class、MyCat.class文件拷进来,如下:

此时再次运行:

依然是由系统类加载器来加载,也很好理解,还是由于工程当中已经有了该字节码文件了,好,接下来将工程中的MySample.class和MyCat.class两个字节码文件删除掉:

再次运行:

原因也如以前学习所分析的,因为系统类加载器加载不了最终就交由咱们自己的类加载器来加载了,也就是MySample里面关联的MyCat类也会由咱们自定义的类加载器所加载,比较好理解,接下来继续看,重新编译,此时MySample.class和MyCat.class文件都存在于工程当中了,下面只删除MyCat.class:

但是不要忘了桌面上这两个Class文件都有,那此时结果又会如何呢?

下面分析一下原因:

那关键就在于它是由哪个类加载器去加载,这里需要明白:它是由加载了MySample的类加载器去加载的,也就是系统类加载器,很显然是加载不了的,因为MyCat.class从工程中被删除了。

好接着再编译重新生成MySample.class和MyCat.class,这次反过来,只删除MySamle.class,而保留MyCat.class,如下:

编译运行:

居然这次MyCat又木有抛异常了,这是为啥呢?从日志中可以看到MySample类此时是由咱们自定义的loader1来加载的,那根据之前的原则,它里面的MyCat类也得由咱们自定义的类加载器所加载,但是根据父亲委派机器会先委派父类应用类加载器去加载,而在工程中已经有MyCat这个字节码文件了,所以最终由系统类加载器加载它。

目前MySample类对MyCat进行了引用,但是MyCat木有引用其它类,这里将其改成也依赖MySample,如下:

再重新编译,此时MySample.class和MyCat.class都已经存在于工程当中了,运行:

比如好理解,都是系统类加载器来加载了。此时将最新生成的MySample.class和MyCat.class文件拷贝至桌面的路径当中:

然后将工程当中的MySample.class文件删除:

再次运行:

居然抛异常了,为什么呢?下面细分析一下:

这里就又涉及到命名空间的概念了,先来回顾一下:

其中标红的这句话最为关键,进一步解决它也就是说由于加载器所加载的类是能看到父加载器所加载的类的,但是反过来则不成立了,也就是由父加载器所加载的类是看不到子加载器所加载的类的, 用这个理论就可以解释为啥要抛异常了,如下:

好,依据这个命名空间的概念下面再来改造程序:

编译一下,此时工程当中又有MySample.class和MyCat.class文件了,再次运行:

这没啥可解释的,接着再将最新生成的MySample.class和MyCat.class拷贝至桌面上,然后依然将MySample.class从工程目录中删除,那此时的输出又会如何呢?

原因是什么呢?还是依据命名空间的这句“由子加载器所加载的类是能看到父加载器所加载的类的”观点:

所以关于命名空间重要说明如下:

  • 子加载器所加载的类能够访问父加载器所加载的类;
  • 父加载器所加载的类无法访问到子加载器所加载的类;

posted on 2018-06-08 13:54  cexo  阅读(516)  评论(1编辑  收藏  举报

导航