【问题标题】:java - How to retrieve anything inside methodjava - 如何检索方法内的任何内容
【发布时间】:2015-06-23 05:22:13
【问题描述】:

据我所知,java 无法检索方法内部的任何内容。所以我在 javac 中使用选项 -g 或 -g:vars。

例如:

class Test {
    int a=0;
    void method(boolean boo){
        String b;
        try
        {
            new Thread().sleep(1000);
        }
        catch(InterruptedException e){}
        JOptionPane.showMessageDialog(null,"test");
        BufferedImage image=ImageIO.read(new File("C:\\file.png"));
    }
}

所以,我使用 BCEL 来检索局部变量。

import org.apache.bcel.classfile.*;
import org.apache.bcel.Repository;
class javap
{
    public static void main(String[]args)
    {
        try
        {
            JavaClass jc = Repository.lookupClass("test");
            ConstantPool constantPool = jc.getConstantPool();
            Method [] method=jc.getMethods();
            for (Method m : method) 
            {
                LocalVariableTable lvt=m.getLocalVariableTable();
                LocalVariable[] lv=lvt.getLocalVariableTable();
                for(LocalVariable l : lv)
                {   
                    System.out.println(l.getName()+" : "+l.getSignature());
                }
            }
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
    }
}

但如果变量没有像String b 那样初始化,它就不起作用。此外,我还想跟踪 new Thread()new File() 之类的构造函数调用以及静态方法的调用以及 JFileChooser 内部的初始化,例如 new FileJOptionPane。所以我想在输出中看到ThreadString bJOptionPaneImageIOFile

我应该怎么做才能让它们打印在我的程序中?

【问题讨论】:

  • "但如果变量未初始化或构造函数调用未在变量中命名,则它不起作用。" - 我知道英语不是你的第一语言,但我真的不明白你在这里想说什么。你能改写一下,这样你在说什么就更清楚了吗?

标签: java methods constructor local-variables bcel


【解决方案1】:

您根本无法获取b 变量,因为java 编译器(至少javac 和ecj)根本不会将其放入生成的类文件中:如果未分配变量,则不会分配变量槽并且不会存储它在本地变量表中。您可以创建名称较长的未使用变量,例如String blahblah;,编译类,在文本编辑器中打开编译的.class 文件并搜索blahblah 字符串。你不会找到它。所以BCEL不能帮你找到不存在的变量。

如果你想跟踪新对象的创建和静态方法的调用,你可以扫描方法字节码。使用 BCEL 最简单的方法是使用 MethodGen(即使您不想生成新方法)。完整代码如下:

import org.apache.bcel.Constants;
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.ConstantMethodref;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.LocalVariable;
import org.apache.bcel.classfile.LocalVariableTable;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.NEW;

class javap
{
    public static void main(String[]args)
    {
        try
        {
            JavaClass jc = Repository.lookupClass("Test");
            ConstantPool constantPool = jc.getConstantPool();
            Method [] method=jc.getMethods();
            for (Method m : method) 
            {
                LocalVariableTable lvt=m.getLocalVariableTable();
                LocalVariable[] lv=lvt.getLocalVariableTable();
                for(LocalVariable l : lv)
                {   
                    System.out.println(l.getName()+" : "+l.getSignature());
                }
            }
            ConstantPoolGen cpg = new ConstantPoolGen(constantPool);
            for(Method m : method)
            {
                MethodGen mg = new MethodGen(m, m.getName(), cpg);
                for(InstructionHandle ih = mg.getInstructionList().getStart(); 
                        ih != null; ih = ih.getNext())
                {
                    if(ih.getInstruction() instanceof NEW) 
                    {
                        NEW newInst = ((NEW)ih.getInstruction());
                        String className = constantPool.getConstantString(
                            newInst.getIndex(), Constants.CONSTANT_Class);
                        System.out.println("Class instantiation: "+className);
                    }
                    if(ih.getInstruction() instanceof INVOKESTATIC) 
                    {
                        INVOKESTATIC newInst = ((INVOKESTATIC)ih.getInstruction());
                        String className = constantPool.getConstantString(
                                ((ConstantMethodref) constantPool
                                        .getConstant(newInst.getIndex()))
                                        .getClassIndex(),
                                Constants.CONSTANT_Class);
                        System.out.println("Static call: "+className);
                    }
                }
            }
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
    }
}

输出如下:

this : LTest;
this : LTest;
boo : Z
Class instantiation: java/lang/Thread
Static call: java/lang/Thread
Static call: javax/swing/JOptionPane
Class instantiation: java/io/File
Static call: javax/imageio/ImageIO

请注意,您有两次java/lang/Thread,因为new Thread() 被捕获为对象创建,Thread.sleep() 被捕获为静态方法调用。

【讨论】:

  • 没有在变量中命名的构造函数调用怎么样?
  • 对不起,我不知道这叫什么。但感谢您的编辑。
  • JOptionPane 和 ImageIO 怎么样?
  • 似乎您也想跟踪静态方法调用。这实际上是一样的。您只需要检查指令是否为INVOKESTATIC 并从它所引用的 MethodRef 常量中提取类名。
  • 你能举个例子吗?我是使用 BCEL 的初学者。
猜你喜欢
  • 2021-12-30
  • 2014-01-07
  • 2013-05-04
  • 2013-04-01
  • 2021-11-20
  • 1970-01-01
  • 2011-03-13
  • 2021-11-08
  • 1970-01-01
相关资源
最近更新 更多