zhangxiaoben16 2010-02-25 01:05
浏览 589
已采纳

自定义classloader抛出java.lang.LinkageError异常

[color=red]自己实现了一个classLoader,代码如下[/color]

[color=red]类 SuC [/color]
package com.load;

public class SuC {
}

[color=red]接口 InterTest [/color]
package com.load;

public interface InterTest {

}

[color=red]类 TestIt[/color]
package com.load;

public class TestIt extends SuC implements InterTest {

}

[color=red]主类 MyClassLoader[/color]
[size=medium]package com.load;

import java.io.InputStream;
import java.lang.reflect.Method;

public class MyClassLoader extends ClassLoader{
public Class create() throws Exception{

             [color=green] //装载TestIt这个类[/color]      
              InputStream is = this.getClass().getClassLoader().getResourceAsStream("com/load/TestIt.class");
    int le = is.available();
    byte[] b = new byte[le];
    is.read(b, 0, le);
    Class cls = defineClass("com.load.TestIt",b,0,b.length);

              [color=green]//使用反射看看app加载器里是否装载[/color]      
              ClassLoader classLoader = getSystemClassLoader();
    Method method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
    method.setAccessible(true);
    Object ccl = method.invoke(classLoader, "com.load.SuC");

              [color=green]//输出一下[/color]       System.out.println(ccl);
    System.out.println(((Class)ccl).getClassLoader());
    System.out.println(findLoadedClass("com.load.SuC").getClassLoader());

    [color=green]//装载TestIt的父类[/color]        InputStream iss = this.getClass().getClassLoader().getResourceAsStream("com/load/SuC.class");
    int lee = iss.available();
    byte[] bb = new byte[lee];
    iss.read(bb, 0, lee);
    Class clss = defineClass("com.load.SuC",bb,0,bb.length);

    return cls;
}
public static void main(String []args) throws Exception{
    MyClassLoader myCla = new MyClassLoader();
    myCla.create();
}

}[/size]

[size=medium][color=darkred] main方法中调用create方法,装载TestIt这个类,没有问题,利用反射输出一下,发现TestIt的父类SuC已经被系统类加载器加载。此时再去用defineClass加载SuC的字节流,则会抛出异常。[/color][/size]

[color=red]class com.load.SuC
sun.misc.Launcher$AppClassLoader@19821f
sun.misc.Launcher$AppClassLoader@19821f
Exception in thread "main" java.lang.LinkageError: loader (instance of com/load/MyClassLoader): attempted duplicate class definition for name: "com/load/SuC"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at com.load.MyClassLoader.create(MyClassLoader.java:30)
at com.load.MyClassLoader.main(MyClassLoader.java:45)[/color]

[color=red] 如果不加载SuC就没事。
或者SuC放在TestIt之前也没事,此时调整一下代码[/color][size=medium]package com.load;

import java.io.InputStream;
import java.lang.reflect.Method;

public class MyClassLoader extends ClassLoader{
public Class create() throws Exception{

    InputStream iss = this.getClass().getClassLoader().getResourceAsStream("com/load/SuC.class");
    int lee = iss.available();
    byte[] bb = new byte[lee];
    iss.read(bb, 0, lee);
    Class clss = defineClass("com.load.SuC",bb,0,bb.length);

    InputStream is = this.getClass().getClassLoader().getResourceAsStream("com/load/TestIt.class");
    int le = is.available();
    byte[] b = new byte[le];
    is.read(b, 0, le);
    Class cls = defineClass("com.load.TestIt",b,0,b.length);



    ClassLoader classLoader = getSystemClassLoader();
    Method method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
    method.setAccessible(true);
    Object ccl = method.invoke(classLoader, "com.load.SuC");

    System.out.println(findLoadedClass("com.load.SuC").getClassLoader());
    System.out.println(ccl);
    System.out.println(((Class)ccl).getClassLoader());





    return cls;
}
public static void main(String []args) throws Exception{
    MyClassLoader myCla = new MyClassLoader();
    myCla.create();
}

}[/size]

[color=red]输出com.load.MyClassLoader@c17164
null
Exception in thread "main" java.lang.NullPointerException
at com.load.MyClassLoader.create(MyClassLoader.java:32)
at com.load.MyClassLoader.main(MyClassLoader.java:42)[/color]

[size=medium][color=darkred]我想问的是为什么SuC做为父类在TestIt被加载后,它自己被系统classloader加载。为何用在MyClassLoader里用defineClass再去加载字节流会出现java.lang.LinkageError的异常呢?MyClassLoader的实例应该没有加载过SuC。[/color][/size]

  • 写回答

3条回答 默认 最新

  • iteye_13010 2010-03-01 11:05
    关注

    defineClass中调用的native方法中判断

    http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html
    默认的parent是SystemClassLoader

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 我需要全国每个城市的最新小区名字等数据。
  • ¥15 开发一个小区生态的小程序
  • ¥15 MddBootstrapInitialize2失败
  • ¥15 LCD Flicker
  • ¥15 Spring MVC项目,访问不到相应的控制器方法
  • ¥15 esp32在micropython环境下使用ssl/tls连接mqtt服务器出现以下报错Connected on 192.168.154.223发生意外错误: 5无法连接到 MQTT 代理,如何解决?
  • ¥15 关于#genesiscsheel#的问题,如何解决?
  • ¥15 Android aidl for hal
  • ¥15 STM32CubeIDE下载程序报错
  • ¥15 微信好友如何转变为会员系统?(相关搜索:小程序)