1

我是 java 新手,(我曾经在 .NET、Lua 中编程……)并且我开始使用 ASM。所以我不能使用“Foo”类的任何方法,我该如何调用这些方法?

非常感谢...

代码:

package com.teste;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Opcodes.*;

public class nclass {

public static void main(String[] args) throws Exception {

    Class<?> klass = new ClassLoader(nclass.class.getClassLoader()) {
        public Class<?> defineClass() {

            ClassWriter cw = new ClassWriter(0);
            FieldVisitor fv;
            MethodVisitor mv;
            //
            Label l0;
            Label l1;

            cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
                    "Foo", null, "java/lang/Object", null);

            for (int i = 0; i < 3; i++) {
                fv = cw.visitField(0, "value" + i, "I", null, null);
                fv.visitAnnotation("LBar;", true).visitEnd();
            }

            fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC, "nome", "Ljava/lang/String;", null, null);
            fv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(2, l0);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitInsn(Opcodes.RETURN);
            l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "Lsimple;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "setNome", "(Ljava/lang/String;)V", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(6, l0);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.PUTSTATIC, "simple", "nome", "Ljava/lang/String;");
            mv.visitInsn(Opcodes.RETURN);
            l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("value", "Ljava/lang/String;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "getNome", "()Ljava/lang/String;", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(7, l0);
            mv.visitFieldInsn(Opcodes.GETSTATIC, "simple", "nome", "Ljava/lang/String;");
            mv.visitInsn(Opcodes.ARETURN);
            mv.visitMaxs(1, 0);
            mv.visitEnd();


            cw.visitEnd();

            byte[] bytes = cw.toByteArray();

            return defineClass("Foo", bytes, 0, bytes.length);
        }
    }.defineClass();

    for (Field f : klass.getDeclaredFields()) {
        System.out.println(f + " " + Arrays.toString(f.getAnnotations()));
    }

    for (Field f : klass.getDeclaredFields()) {
        System.out.println(f + " " + f.getName());
    }

    for (Method f : klass.getDeclaredMethods()) {
        System.out.println(f + " " + Arrays.toString(f.getAnnotations()));
    }

    Class<?> c= klass.forName("Foo");

    Method  method = c.getDeclaredMethod ("getNome", String.class);
    System.out.println(method.invoke(c));

   }

}

*新代码工作*

package com;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Opcodes.*;

public class simple {

/**
 * @param args
 * @throws NoSuchMethodException 
 * @throws SecurityException 
 * @throws InvocationTargetException 
 * @throws IllegalAccessException 
 * @throws IllegalArgumentException 
 */
public static void main(String[] args) throws SecurityException,      NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {

    Class<?> klass = new ClassLoader(simple.class.getClassLoader()) {
        public Class<?> defineClass() {

            ClassWriter cw = new ClassWriter(0);
            FieldVisitor fv;
            MethodVisitor mv;
            //
            Label l0;
            Label l1;

            cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
                    "simple", null, "java/lang/Object", null);

            for (int i = 0; i < 3; i++) {
                fv = cw.visitField(0, "value" + i, "I", null, null);
                fv.visitAnnotation("LBar;", true).visitEnd();
            }

            fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC, "nome", "Ljava/lang/String;", null, null);
            fv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(2, l0);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitInsn(Opcodes.RETURN);
            l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "Lsimple;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "setNome", "(Ljava/lang/String;)V", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(6, l0);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.PUTSTATIC, "simple", "nome", "Ljava/lang/String;");
            mv.visitInsn(Opcodes.RETURN);
            l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("value", "Ljava/lang/String;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "getNome", "()Ljava/lang/String;", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(7, l0);
            mv.visitFieldInsn(Opcodes.GETSTATIC, "simple", "nome", "Ljava/lang/String;");
            mv.visitInsn(Opcodes.ARETURN);
            mv.visitMaxs(1, 0);
            mv.visitEnd();


            cw.visitEnd();

            byte[] bytes = cw.toByteArray();

            return defineClass("simple", bytes, 0, bytes.length);
        }
    }.defineClass();

    for (Field f : klass.getDeclaredFields()) {
        System.out.println(f + " " + Arrays.toString(f.getAnnotations()));
    }

    for (Field f : klass.getDeclaredFields()) {
        System.out.println(f + " " + f.getName());
    }

    for (Method f : klass.getDeclaredMethods()) {
        System.out.println(f + " " + Arrays.toString(f.getAnnotations()));
    }
    Method  setNome = klass.getDeclaredMethod("setNome", String.class);
    Method  getNome = klass.getDeclaredMethod("getNome");

    setNome.invoke(klass,"this sucks!");

    System.out.println(getNome.invoke(null));

}

}

感谢 Paŭlo Ebermann,下一步我将尝试使用实例加载类(我认为类似于 "Class s= new simple()" )。

4

1 回答 1

2

看起来你的问题在这里:

 Class<?> c= klass.forName("Foo");

 Method  method = c.getDeclaredMethod ("getNome", String.class);
 System.out.println(method.invoke(c));

klass.forName("Foo")实际上等价于Class.forName("Foo"),这导致Class.forName("Foo", nclass.class.getClassLoader());.

加载的类加载器nclass显然不知道一个Foo类,因为它是由你的匿名类加载器(它是这个类加载器的一个子类)创建的。所以,不要forName在这里使用这个调用,而只是使用你的klass对象来获取方法并调用它。


当然,调用和检索方法的工作方式与您不同。

  • getMethodgetDeclaredMethod在名称旁边采用参数类型列表(不是返回类型) - 在您的情况下没有getNome参数,所以它应该是:

    Method  method = klass.getDeclaredMethod ("getNome");
    
  • 调用方法的第一个参数是接收类型的方法的对象(Foo在您的情况下),或者null用于静态方法。以下参数是方法的参数(即在您的情况下没有参数)。所以你应该在这里使用:

    System.out.println(method.invoke(null));
    

    在您的情况下,可能只是忽略了该参数,因此c可能不会出错。但是,如果您实际上不是Class通过反射调用类的方法,那么在这里仍然没有理由使用类对象。

这一切都是假设您的错误发生在您的forName通话中,而不是更早发生。请学会描述你的错误信息,这样我们就不用猜测了。

于 2011-03-30T22:08:54.227 回答