如何使用ASM访问内部类的方法?

时间:2019-01-22 02:29:30

标签: java bytecode java-bytecode-asm

我正在尝试在.class文件中打印所有方法的说明。下面的代码仅打印出外部类的方法(main)的指令。

如何访问内部类的方法?我读到可以像加载外部类一样加载内部类。我该怎么办?

import java.io.InputStream;
import java.io.FileInputStream;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.List;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.*;
import org.objectweb.asm.util.*;

public class ClassInfoReader {

    public static void main(String[] args) throws Exception{
        InputStream in = new FileInputStream("MyInfo.class");
        ClassReader reader = new ClassReader(in);
        ClassNode classNode = new ClassNode();
        reader.accept(classNode,0);
        @SuppressWarnings("unchecked")
        final List<MethodNode> methods = classNode.methods;
        for(MethodNode m: methods){
             InsnList inList = m.instructions;
             System.out.println(m.name);
             for(int i = 0; i< inList.size(); i++){
                 System.out.print(insnToString(inList.get(i)));
             }
        }

        final List<InnerClassNode> classes = classNode.innerClasses;
        System.out.println(classes);
        for(InnerClassNode c: classes){
             System.out.println(c.innerName);
        }
    }

    public static String insnToString(AbstractInsnNode insn){
        insn.accept(mp);
        StringWriter sw = new StringWriter();
        printer.print(new PrintWriter(sw));
        printer.getText().clear();
        return sw.toString();
    }

    private static Printer printer = new Textifier();
    private static TraceMethodVisitor mp = new TraceMethodVisitor(printer);

这部分代码仅显示有关内部类的基本信息,例如内部类的名称,外部类的名称和访问标志。

final List<InnerClassNode> classes = classNode.innerClasses;
        for(InnerClassNode c: classes){
             System.out.println(c.innerName);
        } 

1 个答案:

答案 0 :(得分:2)

嵌套类不是原始Java的一部分。它们仅是在Java 1.1中添加的,因此必须将其改装为现有的classfile格式。因此,在字节码级别,嵌套类只是单独的类文件中的普通类。区别它们的唯一方法是几个元数据属性,这些属性保存有关源级别嵌套类的信息,以进行反射和编译。

因此,访问嵌套类的方法是加载它并像处理其他任何类一样对其进行处理。您已经弄清楚如何获取嵌套类的名称,现在只需要创建一个新的ClassFileReader并递归地加载它们即可。