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

自定义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条)

报告相同问题?

悬赏问题

  • ¥30 Matlab打开默认名称带有/的光谱数据
  • ¥50 easyExcel模板 动态单元格合并列
  • ¥15 res.rows如何取值使用
  • ¥15 在odoo17开发环境中,怎么实现库存管理系统,或独立模块设计与AGV小车对接?开发方面应如何设计和开发?请详细解释MES或WMS在与AGV小车对接时需完成的设计和开发
  • ¥15 CSP算法实现EEG特征提取,哪一步错了?
  • ¥15 游戏盾如何溯源服务器真实ip?需要30个字。后面的字是凑数的
  • ¥15 vue3前端取消收藏的不会引用collectId
  • ¥15 delphi7 HMAC_SHA256方式加密
  • ¥15 关于#qt#的问题:我想实现qcustomplot完成坐标轴
  • ¥15 下列c语言代码为何输出了多余的空格