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

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

关于命名空间的重要说明:【主要看实例四和五】

  1. 子类加载所加载的类能够访问到父类加载器所加载的类;
  2. 父类加载器所加载的类无法访问到子加载器所加载的类。
  • 实例一:

    • public class MyCat {
          public MyCat(){
              System.out.println("MyCat is loaded by:"+this.getClass().getClassLoader());
          }
      }
      
      public class MySample {
         public MySample() {
            System.out.println("MySample is loaded by :" +this.getClass().getClassLoader());
            new MyCat();  //【重要】
         }
      }
      
      public class MyTest17_1 {
          public static void main(String[] args) throws Exception {
              //MyTest16是一个自定义的类加载,在15+16章节中可以找到
              MyTest16 loader1 = new MyTest16("loader1");
              loader1.setPath("C:\\Users\\admin\\Desktop\\");
              Class<?> clazz = loader1.loadClass("Jvm.MySample");  //先加载
              System.out.println("class : " + clazz.hashCode());
              //如果注释掉该行,那么并不会实例化MySample对象,即MySample构造方法不会被调用
              //因此不会实例化MyCat对象,即没有对Mycat进行主动使用,这里就不会加载MyCat Class
              Object object = clazz.newInstance();  //再创建实例
          }
      }
      
      运行结果:
            findClass invoked:Jvm.MySample
            class loader name:loader1
            class : 856419764
            MySample is loaded by :[loader1]
            ---------------------------------
            findClass invoked:Jvm.MyCat
            class loader name:loader1
            MyCat is loaded by:[loader1]
      
      • 结果分析:[前提:删除out中的MySample、MyCat的class文件,copy到桌面Jvm文件夹中]

        • 分割线之前的自己理解;

        • 分割线之后;在MySample中调用new MyCat(),当创建该实例的时候,就会去加载MyCat的class文件,这个时候,还是有MyTest16自定义类加载器去加载文件,所以才会有:

          findClass invoked:Jvm.MyCat
          class loader name:loader1
          MyCat is loaded by:[loader1]
          
  • 实例二:

    • 代码还是上面的代码,[前提:不删除out中的MySample文件,删除MyCat的class文件]
      • 此时在加载MySample的时候,可以在out文件找找到对应的class文件,所以是由系统类加载器加载的;当我们去在MySample中加载Mycat时候,由于用到的加载器和MySample是同一个,即系统类加载器,但是我们删除了out文件夹中的Mycat.class文件,所以加载不到:NoClassDefFoundError
    运行结果:
       class : 1761291320
       MySample is loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
       Exception in thread "main" java.lang.NoClassDefFoundError: Jvm/MyCat
          at Jvm.MySample.<init>(MySample.java:6)
          ......
    
  • 实例三:

    • 代码还是上面的代码,[前提:不删除out中的MySample文件,而只删除MyCat的class文件]

      • 对于MySample来说,由于out文件夹中没有对应的class文件,所以由自定义类加载加载。

      • 对于MyCat来说,MyCat是由加载MySample使用的类加载器(MyTest16,即loader1)去加载,这个时候,又由双亲委托机制可以知道的是 ,loader1会委托它的父亲去加载MyCat ,所以,最终MyCat 由系统类加载器加载。

        运行结果:
           findClass invoked:Jvm.MySample
           class loader name:loader1
           class : 783286238
           MySample is loaded by :[loader1]
           MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
        
  • 实例四:

    • 由子加载器所加载的类可以看到父加载器所加载的类,但,由父加载器所加载的类看不见子加载器所加载的类。

      • 所有的不改变,但是在MyCat类中多加一行System.out.println("from MyCat : " +MySample.class); [同时删除out文件夹中的MySample.class文件]。

      • 运行结果前五行没有任何问题,当执行到System.out.println("from MyCat : " +MySample.class);这一句的时候,由于会用到类加载器(加载MyCat的类加载器:AppClassLoader)去找MySample.class文件,**这时,由于AppClassLoader是loader(自定义类加载器)的父类加载器,他看不到子加载器所加载的类(内容),**所以,报错,找不到class文件

        public class MyCat {
            public MyCat(){
                System.out.println("MyCat is loaded by:"+this.getClass().getClassLoader());
                System.out.println("from MyCat : " +MySample.class);  
            }
        }
        
        运行结果:
              findClass invoked:Jvm.MySample
              class loader name:loader1
              class : 783286238
              MySample is loaded by :[loader1]
              MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
              Exception in thread "main" java.lang.NoClassDefFoundError: Jvm/MySample
              ......
              Caused by: java.lang.ClassNotFoundException: Jvm.MySample
        
  • 实例五:【实例五与实例四对比】

    • MySample中多加一行:System.out.println(“from MyCat:”+MyCat.class);【删除out中MySample.class】

      • 主要在运行结果的最后一行,成功打印 from MyCat : class Jvm.MyCat ; 因为MySample由自定义类加载器加载,MyCat 由父类加载器加载;所以,由子类加载所加载的类的命名空间当中,可以访问由父加载器所加载的class对象。

        public class MySample {
            public MySample() {
                System.out.println("MySample is loaded by :" +this.getClass().getClassLoader());
                new MyCat();  //【重要】
                System.out.println("from MyCat : " +MyCat.class);
            }
        }
        
        public class MyCat {
            public MyCat(){
                System.out.println("MyCat is loaded by:"+this.getClass().getClassLoader());
            }
        }
        
        运行结果:
           findClass invoked:Jvm.MySample
           class loader name:loader1
           class : 783286238
           MySample is loaded by :[loader1]
           MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
           from MyCat : class Jvm.MyCat
        
发布了25 篇原创文章 · 获赞 0 · 访问量 1453

猜你喜欢

转载自blog.csdn.net/qq_40574305/article/details/104793438