深入理解JVM(学习过程) (9)

​ 可以打印出各个加载器加载的目录: System.getProperty("上述的地址");

public class MyPerson{ private MyPerson myperson; public void setMyPerson(Object object){ this.myperson = (MyPerson) object } } public class MyTest20{ psvm{ MyTest16 loader1 = new MyTest16("loader1"); MyTest16 loader2 = new MyTest16("loader2"); Class<?> clazz1 = loader1.loadClass("com.erwa.jvm.MyPerson");//系统类加载器加载MyPerson的类 Class<?> clazz2 = loader2.loadClass("com.erwa.jvm.MyPerson");//系统类加载器已经加载过此类。就不会再次加载,直接返回之前加载过的对象。 所以下方的结果为true. sout(clazz1 == clazz2);//结果为true //原因是: loader1的父亲为系统类加载,系统类加载器可以加载MyPerson的类。 到了loader2时,加载时,系统类加载器已经加载过此类。就不会再次加载,直接返回之前加载过的对象。 所以结果为true. //并不是因为 loader1 和loader2 是由MyTest16类生成的同样的实例。 Object object1 = clazz1.newInstance(); Object object2 = clazz2.newInstance(); //发射,取到MyPerson中的set方法 Method methos = clazz1.getMethod("setMyPerson",Object.class); method.invoke(object1,object2);// 这个地方可以正常运行 } } // 命名空间深度剖析 //命名空间,由该加载器及所有父加载器加载的类组成 public class MyTest20{ psvm{ MyTest16 loader1 = new MyTest16("loader1"); MyTest16 loader2 = new MyTest16("loader2"); loader1.setPath("user/erwa/Desktop/"); loader2.setPath("user/erwa/Desktop/"); //然后把编译生成的class文件剪贴到桌面上。此时,执行此类的输出结果是什么? Class<?> clazz1 = loader1.loadClass("com.erwa.jvm.MyPerson");//自定义加载器1加载MyPerson的类 Class<?> clazz2 = loader2.loadClass("com.erwa.jvm.MyPerson");//自定义加载器2加载MyPerson的类 // clazz1 和clazz2加载的文件不在同一个命名空间中。 sout(clazz1 == clazz2);//结果为false //原因是: loader1的父亲为系统类加载,系统类加载器不能加载MyPerson的类,由自定义加载器加载。 到了loader2时,加载时同loader1,由自定义加载器的实例再次加载,直接返回之前加载过的对象。 所以结果为true. //并不是因为 loader1 和loader2 是由MyTest16类生成的同样的实例。 Object object1 = clazz1.newInstance(); Object object2 = clazz2.newInstance(); //发射,取到MyPerson中的set方法 Method methos = clazz1.getMethod("setMyPerson",Object.class); method.invoke(object1,object2); //并且这个地方抛异常 } }

image-20200210222934649

image-20200210222615920

类加载器命名空间总结

类加载器的双亲委托模型的好处:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfdfy.html