在运行时检查类是代码的一部分还是依赖项的一部分

Check at runtime whether a class is part of the code or part of one of the dependencies

提问人:Hofi 提问时间:11/13/2023 更新时间:11/13/2023 访问量:41

问:

我正在开发一个引擎,该引擎使用 Java Reflect 库来获取类及其超类的方法。为了进行分析,我需要知道哪些方法是由超类继承的,以及超类是其中一个库的一部分,还是该类是项目本身的一部分。有什么方法可以确定这一点吗?

我尝试使用类加载器,但我要么不知道哪种是正确的方法,要么它不起作用(我宁愿这么认为),因为类加载器也可以加载依赖项的类。

此外,一个项目可能有许多模块和包,这使得(在我的机会下,但也许我错了)无法使用包,该类是其中的一部分。

Java 反射

评论

1赞 Holger 11/13/2023
对你来说,图书馆或项目是什么?如果你不能毫不含糊地命名映射到库或项目的技术工件,我们就无法为你做到这一点,尤其是在你已经排除了直接的候选者(包、模块等)之后。

答:

1赞 queeg 11/13/2023 #1

您需要将问题分为几个不同的步骤:

  • 一个类的父类是什么?
  • 从哪里加载一些类?
  • 源是否从主模块加载了类?

一个类的父类是什么?

在任何实例上,您都可以使用 .getClass() 方法,也可以直接在代码中引用类似 String.class 的内容。

获得类后,运行 getSuperclass() 以查找父类。 请注意,这并不关心实现的接口。

从哪里加载一些类?

在通过遍历继承树获得的每个类上,都可以运行 getClassloader()。根据类加载器本身,您可以获得更多信息。

此外,getPackage() 信息将为您提供有关该类的一些信息。但是,可以将包拆分到不同的 jar 文件和类加载器之间,这使得检测有点棘手。

一个非常强大的解决方案是获取从中加载类的 URL。为此,请向类(或类加载器)询问该类的 URL,如下所示:

Class clazz = ... (some class in question)
URL location = clazz.getResource('/' + clazz.getName().replace('.', '/') + ".class");

有了它,您将收到类似

jar:file:/jdk/jre/lib/rt.jar!/java/lang/Object.class

源是否从主模块加载了类?

现在这一切都归结为比较 URL 字符串。只需查看感叹号之前的部分,您应该有一个 jar 文件。答案现在应该很容易了。

评论

2赞 Holger 11/13/2023
对于顶级类,可以简化为 .但是从 Java 9 开始,et al 的结果将是这样的。clazz.getResource('/' + clazz.getName().replace('.', '/') + ".class")clazz.getResource(clazz.getSimpleName() + ".class")Object.classjrt:/java.base/java/lang/Object.class
0赞 queeg 11/14/2023
嗯。这可能意味着我们必须区分 Java9+ 或模块化应用程序。那里的 URL 是否仍然具有可比性?请随时更新我的答案。