类加载器命名空间深度解析与实例分析

在上一次【https://i.cnblogs.com/posts?categoryid=1154466】最后写了一个貌似没啥意义的程序,回顾一下:

其结果为true的原因并非是因为loader1和loader2都是MyTest16的实例哈,如果是这样理解的话说明对类的双亲委托机制就不太了解,这里再解释一下原因:

貌似程序也没有异常都能正常执行,那写它有啥意义呢?其实写它是有目的的,这次会基于它进一步进行修改,最终会发现一个非常惊奇的异常,下面进行改造:

很显然直接运行其结果跟之前一样,因为还是由系统类加载器去加载,工程中有MyPerson.class文件,如下:

此时咱们将工程当中生成的MyPerson.class文件拷至到桌面的指定目录下:

然后将MyPerson.class从咱们的工程当中删除掉:

那此时再运行结果又会如何呢?

呃~~抛异常了,下面来分析一下:

其中为啥返回false的更深层次的原因还是跟命名空间相关,具体是:clazz1是由loader1所加载的,而calzz2是由loader2加载的,而loader1和loader2从双亲的层次关系来看这两者是没有任何关系的,也就会在JVM中形成两个命名空间,也就是两个独立的内存,具体原因还是之前所学习理论如下:

也就是咱们目前的情况就属于图上的第三点:虽说clazz1和clazz2的完整名字及类的包名都是一模一样的,但是它俩是属于不同的命名空间,另外为了更进一步理解还需引入另一个理论:不同类加载器的命名空间关系,具体如下:

  • 同一个命名空间内的类是相互可见的。
  • 子加载器的命名空间包含所有父类加载器的命名空间。因此由子加载器加载的类能看见父加载器加载的类,例如系统类加载器回载的类能看见根类加载器加载的类。
  • 由父类加载器加载的类不能看见子加载器加载的类。
  • 如果两个加载器之间没有直接或间接的父子关系,那么它们各自加载的类相互不可见。【符合咱目前的场景】

既然不可见那很显然clazz1和clazz2是两个不同的对像,那当然返回false喽,所以可见命名空间是多么的重要,所以也反复被提及到。

继续往下分析结果:

这也是写这个程序目的之所在,让咱们会觉得非常之惊奇,而如果根据咱们目前分析的上下文来理解那就变得理解应当了,因为clazz1和clazz2在不同的命名空间里面而又不是父子关系所以是相互不可见的,所以:

那为啥这个程序要这样设计专门在MyPerson中传一个Object然后进行向下类型转换,而不是直接传一个Person类型的参数呢?这是有原因的,咱们来试一下:

然后重新编译,然后再将MyPerson.class重新拷贝到桌面,并且将工程当中的MyPerson.class给删除掉,然后再运行:

所以还是将代码还原成Object参数类型。

猜你喜欢

转载自www.cnblogs.com/webor2006/p/9157847.html