Class与Class的实例
类加载器加载的class对象也就是得到一个Class对象,可能让人闹混的也就是Class的实例对象,这个主要是为了让大家看下面的时候区别实例和Class对象。
public class MyTest4 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
MyClassLoader loader1 = new MyClassLoader("loader1");
MyClassLoader loader2 = new MyClassLoader("loader2");
System.out.println(loader1 == loader2);
System.out.println(loader1.getClass() == loader2.getClass());
}
}
上面的代码运行一下第一个输出的结果为false第二个为true。这个结果看起来是非常简单,大部分稍微了解Java的都能知道。得到这样的正常结果也是非常的简单,但是让两个类的看起来一样的class不一样就需要我们类加载器的知识了,闲话少说我们进入正题。
命名空间
这个博客呢,也就是为了补一下上一个博客的东西。命名空间也就是由本加载器和父类加载器共同组成的,子加载器可以访问父类加载器加载的类,父类不能访问子类加载器所加载的类,而没有什么关系的加载器,就算是兄弟加载器(父加载器为一个)的两个命名空间中的Class也是相互不可见的。
通过这简单的描述说明不了什么,看一下代码实例,实例很难想。。烦躁
下面的代码设计了自定义类加载器,可以跳转到上一篇博客请点击这里查看。
先来一个简单的小例子
ublic class MyTest4 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
MyClassLoader loader1 = new MyClassLoader("loader1");
MyClassLoader loader2 = new MyClassLoader("loader2");
loader1.setPath("C:\\Users\\13559\\Desktop\\jvmtest\\");
loader2.setPath("C:\\Users\\13559\\Desktop\\jvmtest\\");
Class<?> clazz1 = loader1.loadClass("com.programer.wenbin.jvm.TestUse");
Object object1 = clazz1.newInstance();
Class<?> clazz2 = loader2.loadClass("com.programer.wenbin.jvm.TestUse");
Object object2 = clazz2.newInstance();
Class<?> clazz3 = loader2.loadClass("com.programer.wenbin.jvm.TestUse");
Object object3 = clazz3.newInstance();
System.out.println(object1.getClass());
System.out.println(object2.getClass());
System.out.println(object1.getClass() == object2.getClass());
System.out.println(object3.getClass() == object2.getClass());
}
}
结果
----------------------This is MyClassLoader------------------
----------------------This is MyClassLoader------------------
class com.programer.wenbin.jvm.TestUse
class com.programer.wenbin.jvm.TestUse
false
true
也就是说这是两个不相关的加载器,尽管父加载器都是系统类加载器(AppClassLoader),但是由于系统类加载器并无法无法加载这个类,因为已经把自动的的class文件删除了,加载的是本人指定路径下的class文件。如果不这样的话(双亲委托机制)都是由AppClassLoader加载,那么余小宁结果得到的将是两个true,相信大家看着到这里之前已经运行过,结果都为true的看到这里可以改变一下class文件的路径。也就能实现如上效果。
这样的在我们开发中可能并不常见,打假也可能会这都能调用了中的方法可能并不会影响什么,那么大家看下面的这个报错信息。
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.programer.wenbin.jvm.MyTest4.main(MyTest4.java:17)
Caused by: java.lang.ClassCastException: com.programer.wenbin.jvm.TestUse cannot be cast to com.programer.wenbin.jvm.TestUse
at com.programer.wenbin.jvm.TestUse.setTest(TestUse.java:10)
... 5 more
这样的错误打假也许都见过。
甲:我这报错,类型转换异常。
乙:这简单类型转换不对,你找找,是不是赋值的时候看错了,报错信息会告诉你什么转什么错了。
甲:我看了,是这个类转这个类异常。
乙:(开始烦躁)你看错了吧,我看看!
甲:呐~,这里
乙:**,这java环境坏了吧~,开始怀疑人生。
如果你不想迷茫,请学习JVM,让你的Java不会怀疑人生
上述例子的实现如下。
MyTest4
package com.programer.wenbin.jvm;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyTest4 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
MyClassLoader loader1 = new MyClassLoader("loader1");
MyClassLoader loader2 = new MyClassLoader("loader2");
loader1.setPath("C:\\Users\\13559\\Desktop\\jvmtest\\");
loader2.setPath("C:\\Users\\13559\\Desktop\\jvmtest\\");
Class<?> clazz1 = loader1.loadClass("com.programer.wenbin.jvm.TestUse");
Object object1 = clazz1.newInstance();
Class<?> clazz2 = loader2.loadClass("com.programer.wenbin.jvm.TestUse");
Object object2 = clazz2.newInstance();
Method method = clazz1.getMethod("setTest", Object.class);
method.invoke(object1,object2);
}
}
TestUse
package com.programer.wenbin.jvm;
public class TestUse {
private TestUse test;
public void setTest(Object test) {
this.test = (TestUse) test;
}
}
看到这里相信打假也就能理解两个不是父子也不是爷孙更不是祖宗的关系的时候,彼此加载的类是不可见的。
这也恰恰证明了类加载的双亲委托机制的一个好处就是让公共类(比如Object)的版本唯一,保证不会出现上面让人烦躁的类型转换异常
今天先到这里,明天继续添加父加载器对于子加载器加载的类不可见的例子
未完待续。。。。