【问题标题】:How can I identify declarations and references to external classes and methods within a java program?如何识别 Java 程序中对外部类和方法的声明和引用?
【发布时间】:2019-01-20 16:13:40
【问题描述】:

假设我有两个包(package1,package2),每个包中有一个类(package1.A,package2.B)。我需要使用 java 程序识别从 package1.A 到 package2.B 的引用,反之亦然,并且还需要引用每个类中的任何方法。

代码是这样的:

package package1;
public class A{
    public  A(){
        Class<?> clazz = Class.forName("package2.B");
        Method mthd = clazz.getMethod("someMethod", Integer.TYPE);
}
    public static void main(String[] args) {
        new A(); 
    }

B类是这样的:

package package2;
    public class B {
        public B someMethod(int someParam) {
            return null;
        }
    }

我只需要一些关于我应该如何开始使用解析器来解决这个问题的指示。我必须记住什么样的规则?我的问题的目标是识别依赖关系。

【问题讨论】:

  • 您几乎需要为 Java 编写一个完整的解析器。而且您需要遍历每个源代码文件的解析树,识别每个表达式的类型以查看它是否与您要查找的类匹配。
  • 请非常准确地了解我们在这里谈论的元级别。您是否有一个程序试图在其自己的代码中查找对某个类的引用?您是否正在尝试分析另一组代码?还是您有一个代码库,而您只是想检查它,就像在 IDE 中一样?
  • 哦,我误解了这个问题吗?我以为您是在询问编写一个执行此操作的 Java 程序。你的意思是如何在你的IDE中做到这一点?好的,这使它成为一个不同的问题。您使用的是哪个 IDE?
  • 哦,好的,这太宽泛了,无法在 Stack Overflow 的单个页面上回答。但是对解析器做一些研究——这会让你开始。
  • 检测到这一点已经够难的了,但是在反射代码中检测到这样的东西可能是不可能的。我不想尝试检测这样的事情:String name = String.format("%c%s%c%s", 32, "java.lang", 46, "System"); Class.forName(name.substring(1));

标签: java software-design


【解决方案1】:

我不打算发布这个,因为它不是很好,但是由于已经有几天了,你还没有得到很多回应,这里是根据你的评论的不同类型的答案:

我试图找到两个类之间的依赖关系及其 各种方法。

如果您只需要在您自己的应用程序中查找依赖项和调用(不是外部库),请继续阅读。

考虑在每个方法中注入一两行代码(很容易在编译时由脚本完成?),并记录这些信息。例如,您可以使用object.getClass().??? 的变体来查找有关当前方法的信息,包括其包、类和方法名称。

例如这个只是直接将信息输出到控制台:

StackTraceElement[] ste = Thread.currentThread().getStackTrace();
System.out.println("Called by: "+ste[ste.length - 2].getMethodName());
Object object = new Object(){};
System.out.println("Method details: "+ object.getClass().getPackage().getName() +" - "+ object.getClass().getName() +" - "+ object.getClass().getEnclosingMethod().getName());

对于插入这些行的每个方法,每次调用时都会在控制台上吐出类似的内容:

Called by: source
Method details: myPackage - myClass$1 - myMethod

通过将上述内容分为几个类,对我的一个应用程序进行快速测试的一些实际结果:

Called by: getStackTrace
Method details: testdump - testdump.TestDump$1 - main
Called by: pumpEvents
Method details: testdump - testdump.Rect$1 - paintComponent
Called by: checkFileSize
Method details: update - update.FTP$2 - checkFileSize
Called by: checkFileSize
Method details: update - update.FTP$1 - download
Called by: pumpEvents
Method details: testdump - testdump.Rect$1 - paintComponent
...

我们可以很容易地准确地看到调用的两个不同的包,并且我们通常可以看到它是从哪里调用的,尽管您需要使用ste[ste.length - 2].getMethodName() 来返回不同的行,具体取决于返回多远您想查看的堆栈跟踪。显然,这应该只在调试模式下使用,它会产生很多垃圾,但是根据应用程序的大小,检查输出结果应该是一件简单的事情,无论是手动还是通过制作一个构建的短程序供您检查的依赖关系树。


或者,您也可以以类似的方式使用 Java 9 堆栈遍历 API:https://stackoverflow.com/a/45812871/1270000

【讨论】:

  • 如果您想要关于应用程序之外的类的信息,请大声喊叫,我很高兴删除此答案,以便您获得更多可见性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-11
  • 2020-10-03
  • 1970-01-01
  • 1970-01-01
  • 2017-12-29
  • 2021-03-24
相关资源
最近更新 更多