0 0

使用类加载器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个答案 按时间排序 按投票排序

0 0

采纳的答案

http://www.iteye.com/topic/98178 这个不错 那篇很系统 javaEye就是有很多java牛人。

2012年1月03日 15:28
0 0

其实你这个问题在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
0 0

在java中类加载器不一样 强制转换会报错。改为loadClass使用的类加载器 就与Class.forName使用的一样。

2012年1月01日 18:12
0 0

你的问题我重现了,但是我跟你一样迷惑,所以弄了一会儿。饭都玩了吃。
增加一个类

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
0 0

Class c = oucl.findClass("kite.jvm.Constant");   

改为
Class c = oucl.loadClass("kite.jvm.Constant");   

就可以了

2012年1月01日 17:48
0 0

到时给你看看 !

2012年1月01日 13:41

相关推荐

    java反序列化漏洞URLClassLoader利用1

    为了防御这类攻击,开发者应该确保对反序列化的数据进行严格的验证,避免加载不可信的类,同时限制类加载器的权限,特别是对于能够从网络加载类的类加载器,如`URLClassLoader`。 在修复此类漏洞时,可以考虑以下...

    URLClassLoader初体验

    在Java中,类的加载遵循双亲委派模型,`URLClassLoader`会首先尝试在其父类加载器(通常是`BootstrapClassLoader`或`ExtensionClassLoader`)无法找到指定类时进行加载。 在创建`URLClassLoader`实例时,需要提供一...

    Java URLClassLoader动态加载jar包1

    从JDK 1.2开始,`java.net.URLClassLoader`就被引入,以支持从网络或者其他支持URL的来源加载类。 `URLClassLoader`的主要工作原理是通过URL对象定位到类或资源的路径。例如,在提供的代码示例中,创建了一个`...

    使用URLClassLoader加载本地文件夹c盘下的test.jar文件

    URLClassLoader是Java提供的一种类加载器,它允许我们通过URL来加载类和资源,从而实现这一目标。本篇文章将深入讲解如何使用URLClassLoader加载C盘下的test.jar文件。 首先,了解类加载器的基本概念。在Java中,类...

    java 类加载器 双亲委派 根加载器、扩展类加载器、系统类加载器

    类加载器分为根加载器(bootstrap classloader)、扩展类加载器(ext classloader)、系统类加载器(system classloader)、自定义类加载器(通常继承java.net.URLClassLoader,重写findClass()),它们的关系通常...

    Java虚拟机JVM类加载初始化

    - 网络加载:使用`java.net.URLClassLoader`从网络指定的URL加载类。 - 压缩文件加载:从`.jar`、`.zip`等压缩文件中查找并加载类,自动解析`.jar`文件中的`.class`文件。 - 动态编译:从`.java`源代码文件编译成...

    Java 2平台安全技术-结构,API设计和实现

    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 2平台安全技术-结构,API设计和实现

    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 使用...

    jvm 加载class文件

    此示例展示了如何使用`java.net.URLClassLoader`自定义类加载器来加载特定路径下的`TestClassA`类,并调用其中的方法。 #### 六、总结 通过对Java中JVM加载`.class`文件的过程及其类加载器的具体工作原理的介绍,...

    Java高级知识

    - `java.lang.ClassLoader` 和 `java.net.URLClassLoader` - `java.util.ArrayList`、`java.util.LinkedList` - `java.util.HashMap`、`java.util.LinkedHashMap`、`java.util.TreeMap` - `java.util.HashSet`、...

    Jboss管理与开发核心技术(第三版)

    当需要查找类或资源时,通常会先委托给父类装载器进行查找,只有当父类装载器找不到时,才会由当前类装载器继续查找。Java虚拟机(JVM)中有一个特殊的根类装载器,称为引导类装载器(Bootstrap ClassLoader),它是所有...

    JAVA7新特性介绍(官方公布)中文版[参照].pdf

    `URLClassLoader`新增了`close()`方法,这有助于清理和管理类加载器资源,特别是当JAR文件需要更新时,可以更高效地卸载和加载类。 5. **套接字直接协议(SDP)**: Java 7支持SDP,提供了高性能的网络连接,尤其...

    JBoss管理与开发核心技术_第三版电子书

    例如,将`java.net.URL`对象放入`java.util.ArrayList`后,再尝试将其转换为`java.lang.String`类型时会抛出此异常。 - **LinkageError**:在类的初始化过程中发生的错误,通常是由于类依赖关系错误引起的。 - **...

Global site tag (gtag.js) - Google Analytics