【问题标题】:Introspecting Fields inside a Method内省方法中的字段
【发布时间】:2013-12-05 01:38:08
【问题描述】:

有没有什么方法可以通过反射或其他工具来内省 Java 中的方法中的字段?

所以,例如:

public void someMethod() {
  int one = 1;
  int two = 2;
}

然后反省在方法“someMethod”中查找 int 类型的字段“one”和“two”?据我所知,反射是不可能的,但我希望 ASM 或其他一些字节码自省工具能够做到。

【问题讨论】:

  • 这些是局部变量,不是字段。
  • 虽然这个问题之前可能已经被问过,但在所有这些回答中,没有一个示例说明如何使用 ASM 之类的工具访问“局部变量”。
  • @darkfrog:stackoverflow 不是为了喂你。提到的问题有答案,告诉你如何。 尝试一下并询问您是否有具体问题。
  • @Holger,不是在寻找勺子喂食,但就像我已经说过的那样,实际上没有一个响应给出如何在任何库中完成此任务的答案。他们只是含糊地暗示可能在 ASM 中这样做。我已经深入研究了 ASM,但还没有找到任何关于如何实现这一点的信息。

标签: java api reflection bytecode


【解决方案1】:

字段与方法局部变量的不同之处在于:

  • 首先,方法中的变量在以字节码表示时不会有名称。
  • 其次,允许编译器优化这些变量。没有合同说这些方法局部变量必须由编译器保存。同时,编译器可以根据需要添加任意数量的局部变量。

还有另一个问题:在字节码中,局部变量没有通过显式声明指定,其方式与在 Java 源代码中声明的方式类似。相反,方法局部变量仅作为特定于方法的变量数组的一部分可见,该数组按此顺序包含以下所有变量:

  • 对调用方法的对象的引用(只要方法不是static,则不包括此引用),这就是this 引用。
  • 按源代码中定义的顺序引用此方法的所有参数。
  • 对方法中创建的所有局部变量的引用:

本例中类似 m 的方法:

class A {
  void m(Object arg) {
    Object o = "test";
  }
}

因此将在字节码中显示为以下局部变量数组:

[Object (this), Object (arg), Object (o)]

有了这些知识,您可以使用 ASM 及其 MethodVisitor 解析类的方法。这样做,你可以扣除:

  1. 局部变量数组的大小为三个,假设您可以有三个局部变量
  2. 你会发现方法不是static,因此你可以把第一个变量划掉,剩下两个局部变量的可能性。
  3. 该方法有一个类型为 reference 的参数,因此您可以删除另一个变量,这可能会留下一个局部变量声明。

现在您必须解析方法的字节码,您会发现有一个String 类型的引用被推入第三个数组位置。这会让您发现您声明了一些类型为String 的局部变量或其超类型之一,例如Object

但是,您仍然无法确定此局部变量是否是综合添加的。出于上述原因。没有更多信息可以为您找到。 (注意 longdouble 变量,这些变量占用大小为 2 的变量点。)

【讨论】:

  • 值得注意的是,具有分离作用域的变量可能在字节码级别共享相同的槽。还有一个合成变量的实际例子:for-each 循环生成这样的变量。
  • 确实如此,但前提是它们的类型相同。您不能重复使用两个 Objects 的位置来将 long 存储在另一个范围内。
  • 对不起,你错了,你可以重复使用任何变量槽,我刚刚试了一下,它可以工作。我什至没有破解字节码,我只是使用 eclipse 编译了{ Object o1="o1", o2="o2"; } { long l1=0L; },它只创建了两个本地变量,将两个插槽重用于long
  • 确实,我不知道。可能是您不能将两个整数加载为 long,而我现在将其混合在一起。我记得以前遇到过这样的问题,但显然我记错了。
  • 没错,您绝不能尝试读取与之前存储的引用类型、int、float 和 long/double half 不同的类型。并且您不得以可能导致此类尝试的方式进行分支。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-17
  • 1970-01-01
  • 2016-09-05
  • 1970-01-01
  • 2017-03-10
  • 1970-01-01
  • 2012-01-30
相关资源
最近更新 更多