JVM(十) 命名空间

来源:互联网 发布:掌中宝是什么软件 编辑:程序博客网 时间:2024/06/10 05:34

每个类加载器都有自己的命名空间。

和我们Java中的Package的概念是一样的,和XML中的namespace的概念类似。

同一个命名空间内的类是相互可见的,命名空间由该加载器及所有父加载器所加载的类组成。

比如说loader1上面有父加载器,父加载器和所加载的所有的类在一个命名空间里面。子加载器的命名空间包含所有父加载器的命名空间。因此由子加载器加载的类能看见父加载器的类。例如系统类加载器加载的类能看见根类加载器加载的类。由父亲加载器加载的类不能看见子加载器加载的类。如果两个加载器之间没有直接或间接的父子关系,那么它们各自加载类相互不可见。

在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类;在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类。

比如有两个加载器A和B加载同一个类,他们如果不是父子关系的话,A已经把类加载到内存当中,B也可以把类加载到内存当中。但如果A和B是父子关系,那么他们只有先加载的才能将类加载到内存。因为加载的条件首先判断是否已经加载了这个类,如果没有加载则进行加载,如果加载就不会再进行加载。


把博客《JVM(十一) 创建用户自定义的类加载器》的main方法稍做一些变化。

public static void main(String[] aregs) throws Exception{MyClassLoader loader1 = new MyClassLoader("loader1");loader1.setPath("d:\\myapp\\serverlib\\");MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");loader2.setPath("d:\\myapp\\clientlib\\");/*MyClassLoader loader3 = new MyClassLoader(null,"loader3");loader3.setPath("d:\\myapp\\otherlib\\");test(loader2);test(loader3);*/Class clazz = loader1.loadClass("Sample");Object object = clazz.newInstance();Sample sample = (Sample)object;System.out.println(sample.v1);}
输出结果(命令:java MyClassLoader):

Sample is loaded by: loader1
Dog is loaded by :loader1
Exception in thread "main" java.lang.NoClassDefFoundError: Sample
        at MyClassLoader.main(MyClassLoader.java:88)
Caused by: java.lang.ClassNotFoundException: Sample
        at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 1 more

分析:

MyClassLoader类由系统类加载器加载,而Sample类由loader1类加载,因此MyClassLoader类看不见Sample类。在MyClassLoader类的main()方法中使用Sample类,会导致NoClassDefFoundError错误。


当两个不同命名空间内的类相互不可见时,可采用Java反射机制来访问对方实例的属性和方法。如果把MyClassLoader类的main()方法替换为如下代码:

public static void main(String[] aregs) throws Exception{MyClassLoader loader1 = new MyClassLoader("loader1");loader1.setPath("d:\\myapp\\serverlib\\");MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");loader2.setPath("d:\\myapp\\clientlib\\");/*MyClassLoader loader3 = new MyClassLoader(null,"loader3");loader3.setPath("d:\\myapp\\otherlib\\");test(loader2);test(loader3);*//*Class clazz = loader1.loadClass("Sample");Object object = clazz.newInstance();Sample sample = (Sample)object;System.out.println(sample.v1);*/Class clazz = loader1.loadClass("Sample");Object object = clazz.newInstance(); //创建一个Sample类的对象Field field = clazz.getField("v1");int v1 = field.getInt(object);System.out.println("v1:"+v1);}
输出结果:

Sample is loaded by: loader1
Dog is loaded by :loader1
v1:1


如果把D:\myapp\serverlib目录下的Sample.class和Dog.class删除,再把这两个文件拷贝到D:\myapp\syslib目录下,然后运行main()方法,也能正常运行。此时MyClassLoader类和Sample类都由系统类加载器加载,由于它们位于同一个命名空间内,因此相互可见。




0 0
原创粉丝点击