我有这样的代码:
package teste;
public class Teste {
public static void main(String[] args) {
String arroz = "abc";
Integer banana = 123;
vaiBuscar();
}
private static void vaiBuscar() {
Object[] obj = theMagicMethod();
System.out.println(((String) obj[0]));
System.out.println(((Integer) obj[1]));
}
}
输出应为:
abc
123
现在有趣的部分是我唯一可以定义的方法是theMagicMethod()。我需要获取所有变量值这些变量值定义在调用我的上层方法中。如果有办法做到这一点,可能就是通过反射。
总结:如果除了定义方法theMagicMethod()之外,你不能编辑代码的任何部分,那么这个方法应该如何使这个程序的输出是我上面写的那个?
谢谢!
编辑:这真的不需要反射来解决。
在方法中,变量名是丢失的。
Java是一个基于堆栈的机器,所以一个方法看起来像
public int add(int first, int second) {
int sum = first + second;
return sum;
}
将失去sum在字节码中的命名,大致读作
pushInt firstParameter
pushInt secondParameter
addInt
returnInt
请注意,中间变量名称sum
在编译过程中被完全销毁,因此无法从运行时检索它。
然而,还有许多其他项必须通过名称引用,因此它们的名称不会在运行时销毁。其中包括
names of classes
names of members
names of methods
names of enums
names of interfaces
因此可以得到.java
文件中所有已使用名称的子集;但是,这样的子集将不包含任何代码块的内部名称。
现在,如果你在编译时设置了一些调试选项(比如-g
),你可以提高可访问的名称的数量;但是,不能保证您读入的任何类都是在设置了调试标志的情况下编译的(事实上,大多数类都没有设置调试标志来提高加载性能)。
如果你不能为任何类这样做,你也不能为JVM这样做。
现在,如果您想尝试获取JVM中未被破坏的所有信息,您可以使用JDWP(调试连接协议)并查看暴露的内容;然而,我怀疑它是否能够达到"所有",因为它只能读取"类装入器装入的所有内容",并且(记住上面的语句)只有在编译中幸存下来的内容。
在生产代码中使用这样的东西很可能不是一个好主意。
也就是说,我不得不承认我也一直在寻找一种方法来检查堆栈跟踪中的变量:)。这可能是一个愚蠢的想法,但也是一个有趣的想法。
不可能完全不可能。的确,字节码似乎是以一种不可能的方式编译的,但每个调试器都设法做到这一点。但是通过反射是绝对不可能的,而且在没有恶意攻击的情况下访问调用方方法的变量也是不可能的。如果可能的话,您可以转义变量的作用域,而这会毁了垃圾收集器的一天。
在任何情况下,变量名都会丢失(这就是为什么Eclipse的调试器经常简单地将参数显示为"arg1"、"arg2"等)。
您可以尝试编写java代理并使用插装API。首先,您可以看看这篇文章:http://blog.javabenchmark.org/2013/05/java-instrumentation-tutorial.html。Julien Poaletti没有尝试读取变量,但我想你可以以他的例子为基础。
但是,使用海关代理是运营部门不应该允许的。使用风险自负!
这是不可能的。反射不能让你看到方法的内部实现。
在Java中没有办法查看堆栈并提取在堆栈方法堆栈框架中声明的变量或任何值。