【问题标题】:Invoke a bytecode class method, java调用字节码类方法,java
【发布时间】:2011-03-30 21:48:40
【问题描述】:

我是 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()”)。

【问题讨论】:

  • 你的代码的实际结果是什么?

标签: java class assembly java-bytecode-asm


【解决方案1】:

您的问题似乎在这里:

 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 对象来获取方法并调用它。


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

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

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

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

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

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

【讨论】:

  • 我发现了一个错误,我弄乱了一些声明“simple”和“Foo”,然后导致错误,感谢您的快速解释! ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-08
  • 1970-01-01
  • 2014-02-16
  • 1970-01-01
  • 2015-05-03
  • 2013-02-17
  • 2020-08-12
相关资源
最近更新 更多