使用ASM实现接口:ClassCastException

时间:2014-01-09 15:49:09

标签: java class java-bytecode-asm

我正在编写一个需要动态实现接口的应用程序。关于生成类,我没有(明显的)问题:我用javap和反编译器验证了它。

问题是,在我生成类之后我定义并实例化了。最后,我将其转换为已实现接口的类型。

问题在于我被java.lang.ClassCastException: MyGeneratedClass cannot be cast to MyInterface击中,但我在调用MyInterface时确实添加了ClassWriter.visit作为界面。

下面是一个SSCCE,演示了一个名为MyInterface的接口充满void方法的问题。

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

cw.visit(V1_6,
        ACC_PUBLIC | ACC_SUPER,
        "MyGeneratedClass",
        null,
        "java/lang/Object",
        new String[]{MyInterface.class.getName().replace(".", "/"});

{
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
    mv.visitVarInsn(ALOAD, 0);
    mv.visitMethodInsn(INVOKESPECIAL,
            "java/lang/Object",
            "<init>",
            "()V");
    mv.visitInsn(RETURN);
    mv.visitMaxs(0, 0);
    mv.visitEnd();
}

for (Method call : MyInterface.class.getDeclaredMethods()) {
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, call.getName(), Type.getMethodDescriptor(call),  null, null);
    // ...
    mv.visitInsn(RETURN);
    mv.visitMaxs(0, 0);
    mv.visitEnd();
}
cw.visitEnd();
byte[] raw = cw.toByteArray();

try {
    return (MyInterface) new ClassLoader() {
        public Class defineClass(byte[] bytes) {
            return super.defineClass("MyGeneratedClass", bytes, 0, bytes.length);
        }
    }.defineClass(raw).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
    e.printStackTrace();
    return null;
}

打印generatedObject.getClass().getInterfaces()确实显示MyInterface已实施。但是generatedObject instanceof MyInterface返回false,这是我发现矛盾的东西。

有人能说清楚这里发生的事吗?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:4)

我猜这是因为新的类加载器不是加载MyInterface的类加载器的子代,这意味着你最终会得到两个不同的类,尽管它们的外观完全相同。尝试更改

return (MyInterface) new ClassLoader() {

return (MyInterface) new ClassLoader(MyInterface.class.getClassLoader()) {