-
使用类加载器java.net.URLClassLoader时的奇怪问题?5
先写个继承java.net.URLClassLoader的类,如下:package kite.jvm; import java.net.URL; import java.net.URLClassLoader; public class OneURLClassLoader extends URLClassLoader { // 类加载器的parent默认为系统AppClassLoader. public OneURLClassLoader(URL[] urls) { super(urls); } // 使用父类的findClass(String name)方法加载类. public Class findClass(String name) throws ClassNotFoundException { return super.findClass(name); } }
接下来写个接口,如下:package kite.jvm; public interface OneInterface {}
紧接着写个实现上面接口的一个类,如下:package kite.jvm; public class Constant implements OneInterface {}
好了,写个含main方法的类测试下,如下:package kite.jvm; import java.net.URL; public class Run { public static void main(String[] args) throws Exception { // class字节码所在的位置. String dir = "file:/Development/workspace/jvm/bin/"; URL url = new URL(dir); OneURLClassLoader oucl = new OneURLClassLoader(new URL[]{url}); // 用类加载器加载kite.jvm.Constant并返回它的class对象. Class c = oucl.findClass("kite.jvm.Constant"); // 根据class对象c实例化一个对象,用它的接口类型(OneInterface)做类型转换. OneInterface instance1 = (OneInterface) c.newInstance(); // 根据class对象c实例化一个对象,用它的实际类型(Constant)做类型转换. //Constant instance2 = (Constant) c.newInstance(); System.out.println(instance1); //System.out.println(instance2); } }
如上代码运行结果打印如下:kite.jvm.Constant@b6e39f
如果打开注释掉的那两条代码,运行结果打印如下:Exception in thread "main" java.lang.ClassCastException: kite.jvm.Constant cannot be cast to kite.jvm.Constant at kite.jvm.Run.main(Run.java:12)
问题:解释下异常的出现,在此情景中接口和实际类型转化的区别?先谢谢大家了。
注:附件里是源代码。
问题补充:谢谢啊,我等你啊liuqing_2010_07 写道到时给你看看 !
问题补充:如果用loadClass方法加载类的话,将使用委托模式找parent来加载,结果是AppClassLoader来加载,是没有异常的,用findClass方法将直接用OneURLClassLoader类加载器来工作加载,我这里想问的就是:用自己编写的类加载器在加载类(可能是远程网络中某个类)时会出现类型转换的问题,不知道是不是语言特性里有这样的规定,我不清楚,谢谢你的回答。chen_yongkai 写道Class c = oucl.findClass("kite.jvm.Constant");
改为Class c = oucl.loadClass("kite.jvm.Constant");
就可以了
问题补充:非常感谢你的热心帮助,让你吃饭晚了心里有点过意不去 ,看了你的代码,是用Class.forName(String name)来加载类的,那最终会选择AppClassLoader来加载,就避开了OneURLClassLoader,我的问题没有叙述好,其实是这样的:我并不想让代码不出现异常,恰恰这个异常是我最感兴趣的,根据现有的打印信息,我判断不出问题所在,再次感谢。liuqing_2010_07 写道你的问题我重现了,但是我跟你一样迷惑,所以弄了一会儿。饭都玩了吃。
增加一个类public class MyConstant extends Constant{ }
改写Run:public class Run { public static void main(String[] args) throws Exception { Integer a = new Integer(1); Object b = (Object)a; String dir = "file:/test/learn/bin/"; URL url = new URL(dir); OneURLClassLoader oucl = new OneURLClassLoader(new URL[]{url}); // Class c = oucl.findClass("kite.jvm.MyConstant"); Class c = Class.forName("kite.jvm.MyConstant"); OneInterface instance1 = (OneInterface) c.newInstance(); Constant instance2 = (Constant)c.newInstance(); System.out.print(c.newInstance().getClass().getName()); Object instance3 = (Object)c.newInstance(); MyConstant instance4 = (MyConstant)c.newInstance(); System.out.println(instance1); System.out.println(instance2); System.out.println(instance3); System.out.println(instance4); } }
MyConstant 的命名空间为本地,
通过下面的代码后// Class c = oucl.findClass("kite.jvm.MyConstant");
这个就是导致出错的真正原因。实际上是一个类加载器不一致 的原因。你先去了解一下类加载器。我去吃点饭有时间 再给你弄。
问题补充:http://www.iteye.com/topic/98178 中有和我一样的问题,现在了解了。
问题补充:谢谢,现在终于懂了liuqing_2010_07 写道http://www.iteye.com/topic/98178 这个不错 那篇很系统 javaEye就是有很多java牛人。
问题补充:谢谢你了,你说的很详细,我现在懂了anranran 写道其实你这个问题在javaeye我回答很多次了.
OneInterface instance1 = (OneInterface) c.newInstance(); (1)
// 根据class对象c实例化一个对象,用它的实际类型(Constant)做类型转换.
//Constant instance2 = (Constant) c.newInstance();(2)
System.out.println(instance1);
//System.out.println(instance2);
上一个GGMM回答的在java中类加载器不一样,强制转换会报错你能理解这个就好说了.
首先为什么(1)可以,因为OneURLClassLoader在加载Constant的时候发现需要加载
OneInterface(因为他是其接口),因为OneURLClassLoader找不到OneInterface,所以最终委其父也就是appclassloader加载了OneInterface.
而转换后的OneInterface instance1也是appclassloader加载的(其实是同一个,一个类在同一laoder里,不会加载两次),自然不存在问题.
而(2)不可以,因为外部的Constant instance2 是appclassloader加载的,而内部的即C是OneURLClassLoader加载的,当然不能转换.
这里为什么说OneURLClassLoader的父是appclassloader,我想你一定知道,我就不班门弄斧了.
2012年1月01日 03:01
6个答案 按时间排序 按投票排序
-
采纳的答案
http://www.iteye.com/topic/98178 这个不错 那篇很系统 javaEye就是有很多java牛人。
2012年1月03日 15:28
-
其实你这个问题在javaeye我回答很多次了.
OneInterface instance1 = (OneInterface) c.newInstance(); (1)
// 根据class对象c实例化一个对象,用它的实际类型(Constant)做类型转换.
//Constant instance2 = (Constant) c.newInstance();(2)
System.out.println(instance1);
//System.out.println(instance2);
上一个GGMM回答的在java中类加载器不一样,强制转换会报错你能理解这个就好说了.
首先为什么(1)可以,因为OneURLClassLoader在加载Constant的时候发现需要加载
OneInterface(因为他是其接口),因为OneURLClassLoader找不到OneInterface,所以最终委其父也就是appclassloader加载了OneInterface.
而转换后的OneInterface instance1也是appclassloader加载的(其实是同一个,一个类在同一laoder里,不会加载两次),自然不存在问题.
而(2)不可以,因为外部的Constant instance2 是appclassloader加载的,而内部的即C是OneURLClassLoader加载的,当然不能转换.
这里为什么说OneURLClassLoader的父是appclassloader,我想你一定知道,我就不班门弄斧了.
2012年1月03日 14:55
-
在java中类加载器不一样 强制转换会报错。改为loadClass使用的类加载器 就与Class.forName使用的一样。
2012年1月01日 18:12
-
你的问题我重现了,但是我跟你一样迷惑,所以弄了一会儿。饭都玩了吃。
增加一个类public class MyConstant extends Constant{ }
改写Run:public class Run { public static void main(String[] args) throws Exception { Integer a = new Integer(1); Object b = (Object)a; String dir = "file:/test/learn/bin/"; URL url = new URL(dir); OneURLClassLoader oucl = new OneURLClassLoader(new URL[]{url}); // Class c = oucl.findClass("kite.jvm.MyConstant"); Class c = Class.forName("kite.jvm.MyConstant"); OneInterface instance1 = (OneInterface) c.newInstance(); Constant instance2 = (Constant)c.newInstance(); System.out.print(c.newInstance().getClass().getName()); Object instance3 = (Object)c.newInstance(); MyConstant instance4 = (MyConstant)c.newInstance(); System.out.println(instance1); System.out.println(instance2); System.out.println(instance3); System.out.println(instance4); } }
MyConstant 的命名空间为本地,
通过下面的代码后// Class c = oucl.findClass("kite.jvm.MyConstant");
这个就是导致出错的真正原因。实际上是一个类加载器不一致 的原因。你先去了解一下类加载器。我去吃点饭有时间 再给你弄。2012年1月01日 18:03
-
Class c = oucl.findClass("kite.jvm.Constant");
改为Class c = oucl.loadClass("kite.jvm.Constant");
就可以了2012年1月01日 17:48
相关推荐
- at java.net.URLClassLoader.findClass(URLClassLoader.java:382) 问题排查
- at java.net.urlclassloader.findclass_java.lang.ClassLoader与java.net.URLClassLoader学习
- at java.net.urlclassloader.findclass_如何使用URLClassLoader加载* .class文件?
- java中class文件如何加载的_java – 如何使用URLClassLoader加载* .class文件?
- java安全——类加载和Unsafe类(ClassLoader,URLClassLoader)
相关推荐
为了防御这类攻击,开发者应该确保对反序列化的数据进行严格的验证,避免加载不可信的类,同时限制类加载器的权限,特别是对于能够从网络加载类的类加载器,如`URLClassLoader`。 在修复此类漏洞时,可以考虑以下...
在Java中,类的加载遵循双亲委派模型,`URLClassLoader`会首先尝试在其父类加载器(通常是`BootstrapClassLoader`或`ExtensionClassLoader`)无法找到指定类时进行加载。 在创建`URLClassLoader`实例时,需要提供一...
从JDK 1.2开始,`java.net.URLClassLoader`就被引入,以支持从网络或者其他支持URL的来源加载类。 `URLClassLoader`的主要工作原理是通过URL对象定位到类或资源的路径。例如,在提供的代码示例中,创建了一个`...
URLClassLoader是Java提供的一种类加载器,它允许我们通过URL来加载类和资源,从而实现这一目标。本篇文章将深入讲解如何使用URLClassLoader加载C盘下的test.jar文件。 首先,了解类加载器的基本概念。在Java中,类...
类加载器分为根加载器(bootstrap classloader)、扩展类加载器(ext classloader)、系统类加载器(system classloader)、自定义类加载器(通常继承java.net.URLClassLoader,重写findClass()),它们的关系通常...
- 网络加载:使用`java.net.URLClassLoader`从网络指定的URL加载类。 - 压缩文件加载:从`.jar`、`.zip`等压缩文件中查找并加载类,自动解析`.jar`文件中的`.class`文件。 - 动态编译:从`.java`源代码文件编译成...
3.9.1 类加载器的层次 44 3.9.2 java.lang.ClassLoader和授权 46 3.9.3 java.security.SecureClassLoader 49 3.9.4 java.net.URLClassLoader 49 3.9.5 类的路径 50 3.10 java.lang.SecurityManager 51 3.10.1 使用...
3.9.1 类加载器的层次 44 3.9.2 java.lang.ClassLoader和授权 46 3.9.3 java.security.SecureClassLoader 49 3.9.4 java.net.URLClassLoader 49 3.9.5 类的路径 50 3.10 java.lang.SecurityManager 51 3.10.1 使用...
此示例展示了如何使用`java.net.URLClassLoader`自定义类加载器来加载特定路径下的`TestClassA`类,并调用其中的方法。 #### 六、总结 通过对Java中JVM加载`.class`文件的过程及其类加载器的具体工作原理的介绍,...
- `java.lang.ClassLoader` 和 `java.net.URLClassLoader` - `java.util.ArrayList`、`java.util.LinkedList` - `java.util.HashMap`、`java.util.LinkedHashMap`、`java.util.TreeMap` - `java.util.HashSet`、...
当需要查找类或资源时,通常会先委托给父类装载器进行查找,只有当父类装载器找不到时,才会由当前类装载器继续查找。Java虚拟机(JVM)中有一个特殊的根类装载器,称为引导类装载器(Bootstrap ClassLoader),它是所有...
`URLClassLoader`新增了`close()`方法,这有助于清理和管理类加载器资源,特别是当JAR文件需要更新时,可以更高效地卸载和加载类。 5. **套接字直接协议(SDP)**: Java 7支持SDP,提供了高性能的网络连接,尤其...
例如,将`java.net.URL`对象放入`java.util.ArrayList`后,再尝试将其转换为`java.lang.String`类型时会抛出此异常。 - **LinkageError**:在类的初始化过程中发生的错误,通常是由于类依赖关系错误引起的。 - **...