当前位置: 首页 > 面试题库 >

如何找到用Java调用给定方法的所有方法?

宦正诚
2023-03-14
问题内容

我需要获取所有调用者方法的列表,以获取Java感兴趣的方法。有什么工具可以帮助我吗?

编辑:我忘了提到我需要从程序中执行此操作。我使用的是Java Pathfinder,我想将其作为调用我感兴趣的方法的所有方法来运行。


问题答案:

为了分析字节码,我建议使用ASM。给定要分析的类列表,可以使访问者找到您感兴趣的方法调用。下面是一个分析jar文件中类的实现。

请注意,ASM使用带有’/’而不是’。的internalNames。作为分隔符。将目标方法指定为不带修饰符的标准声明。

例如,列出在Java运行时jar中可能正在调用System.out.println(“ foo”)的方法:

java -cp "classes;asm-3.1.jar;asm-commons-3.1.jar" App \
    c:/java/jdk/jre/lib/rt.jar \
    java/io/PrintStream  "void println(String)"

编辑:添加了源代码和行号:请注意,这仅指示每个调用方法的最后一个目标方法调用-原始q只想知道哪些方法。我将其作为练习供读者显示调用方法声明的行号或每个目标调用的行号,具体取决于您实际要执行的操作。:)

结果是:

LogSupport.java:44 com/sun/activation/registries/LogSupport log (Ljava/lang/String;)V
LogSupport.java:50 com/sun/activation/registries/LogSupport log (Ljava/lang/String;Ljava/lang/Throwable;)V

Throwable.java:498 java/lang/Throwable printStackTraceAsCause (Ljava/io/PrintStream;[Ljava/lang/StackTraceElement;)V

885 methods invoke java/io/PrintStream println (Ljava/lang/String;)V



资源:

public class App {
private String targetClass;
private Method targetMethod;

private AppClassVisitor cv;

private ArrayList<Callee> callees = new ArrayList<Callee>();

private static class Callee {
    String className;
    String methodName;
    String methodDesc;
    String source;
    int line;

    public Callee(String cName, String mName, String mDesc, String src, int ln) {
        className = cName; methodName = mName; methodDesc = mDesc; source = src; line = ln;
    }
}

private class AppMethodVisitor extends MethodAdapter {

    boolean callsTarget;
    int line;

    public AppMethodVisitor() { super(new EmptyVisitor()); }

    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
        if (owner.equals(targetClass)
                && name.equals(targetMethod.getName())
                && desc.equals(targetMethod.getDescriptor())) {
            callsTarget = true;
        }
    }

    public void visitCode() {
        callsTarget = false;
    }

    public void visitLineNumber(int line, Label start) {
        this.line = line;
    }

    public void visitEnd() {
        if (callsTarget)
            callees.add(new Callee(cv.className, cv.methodName, cv.methodDesc, 
                    cv.source, line));
    }
}

private class AppClassVisitor extends ClassAdapter {

    private AppMethodVisitor mv = new AppMethodVisitor();

    public String source;
    public String className;
    public String methodName;
    public String methodDesc;

    public AppClassVisitor() { super(new EmptyVisitor()); }

    public void visit(int version, int access, String name,
                      String signature, String superName, String[] interfaces) {
        className = name;
    }

    public void visitSource(String source, String debug) {
        this.source = source;
    }

    public MethodVisitor visitMethod(int access, String name, 
                                     String desc, String signature,
                                     String[] exceptions) {
        methodName = name;
        methodDesc = desc;

        return mv;
    }
}


public void findCallingMethodsInJar(String jarPath, String targetClass,
                                    String targetMethodDeclaration) throws Exception {

    this.targetClass = targetClass;
    this.targetMethod = Method.getMethod(targetMethodDeclaration);

    this.cv = new AppClassVisitor();

    JarFile jarFile = new JarFile(jarPath);
    Enumeration<JarEntry> entries = jarFile.entries();

    while (entries.hasMoreElements()) {
        JarEntry entry = entries.nextElement();

        if (entry.getName().endsWith(".class")) {
            InputStream stream = new BufferedInputStream(jarFile.getInputStream(entry), 1024);
            ClassReader reader = new ClassReader(stream);

            reader.accept(cv, 0);

            stream.close();
        }
    }
}


public static void main( String[] args ) {
    try {
        App app = new App();

        app.findCallingMethodsInJar(args[0], args[1], args[2]);

        for (Callee c : app.callees) {
            System.out.println(c.source+":"+c.line+" "+c.className+" "+c.methodName+" "+c.methodDesc);
        }

        System.out.println("--\n"+app.callees.size()+" methods invoke "+
                app.targetClass+" "+
                app.targetMethod.getName()+" "+app.targetMethod.getDescriptor());
    } catch(Exception x) {
        x.printStackTrace();
    }
}

}
```



 类似资料:
  • 问题内容: 在NetBeans中,如何找出在哪里调用方法? 我在一个大型项目中有一个特定的方法,无法找到它的调用位置。 问题答案: 右键单击方法名称时,会出现“ 查找用法” 菜单项。 或将光标放在方法名称上,然后按+ (查找用法)和++ + (显示“查找用法”结果)。

  • 问题内容: 如果我有两个变量: 在不知道的类的情况下obj,如何调用由其标识的方法methodName? 被调用的方法没有参数,并且有String返回值。 问题答案: 参数标识你需要的非常特定的方法(如果有多个重载可用,如果该方法没有参数,则仅给出methodName)。 然后,你通过调用该方法 同样,.invoke如果没有,请忽略中的参数。

  • 问题内容: 我需要找到一个方法的调用者。是否可以使用stacktrace或反射? 问题答案: 根据Javadocs: 数组的最后一个元素表示堆栈的底部,这是序列中最近的方法调用。 一t有,, 和。 你将不得不尝试确定所需的索引(可能是或)。

  • 问题内容: 在java中,可以获取调用当前方法的类和方法(在其中获得StackTrace的方法)。 我的问题是,我可以获取传递给调用此方法的方法的参数吗? 我需要此来进行调试。 例如: 可以从堆栈跟踪中获取此信息,还是有其他方法? (请注意,我需要能够在运行时执行此操作,并且实际上不能更改baseClass的源,这将成为我的调试类的功能,该类事先不知道源) 谢谢。 问题答案: 我认为使用标准Jav

  • 问题内容: 如何去尝试找到Java中给定类的所有子类(或给定接口的所有实现者)?到目前为止,我有一种方法可以执行此操作,但是我发现它效率很低(至少可以这样说)。方法是: 获取类路径上存在的所有类名称的列表 加载每个类并测试以查看它是否是所需类或接口的子类或实现者 在Eclipse中,有一个很好的功能,称为类型层次结构(Type Hierarchy),可以很有效地显示它。如何进行编程? 问题答案:

  • 问题内容: 如何获取用@ decorator2装饰的给定类A的所有方法? 问题答案: 方法1:基本注册装饰器 我已经在这里回答了这个问题:在Python中通过数组索引调用函数=) 方法2:源代码解析 如果您无法控制 类 定义,而 _ 类 _定义 是您想假设的一种解释,则这是 不可能的 (没有代码的读取- 反射),因为装饰器可以是无操作的装饰器(例如在我的链接示例中)仅返回未修改的函数。(但是,如果