我有这段代码:
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()之外你不能编辑代码的任何部分,那么这个方法应该如何使得这个程序的输出是我上面写的那个?
谢谢!
编辑:这并不需要反思才能解决。任何方式都适合,它只需要工作。
答案 0 :(得分:1)
这是不可能的。反射不会让你看看方法的内部实现。
Java中没有办法查看堆栈并提取堆栈方法堆栈帧中声明的变量或任何值。
答案 1 :(得分:1)
在方法中,变量名称将丢失。
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(调试线协议)并查看暴露的内容;但是,我怀疑它是否能够达到“一切”,因为它只能读取“由类加载器加载的所有内容”和(记住上述语句)只能在编译时幸存下来。
答案 2 :(得分:1)
在生产代码中使用这样的东西很可能是个坏主意。
那就是说,我必须承认我一直在寻找一种方法来检查堆栈跟踪上的变量:)。这可能是一个愚蠢的想法,但它也是一个有趣的想法。
完全无法完全。确实,字节代码似乎是以不可能的方式编译的,但每个调试器都设法完成它。但是通过反射肯定是不可能的,并且在没有肮脏的黑客攻击的情况下也无法访问调用者方法的变量。如果可能的话,你可以逃避变量的范围,并且你会破坏垃圾收集器的那一天。
在任何情况下,变量名都会丢失(这就是为什么Eclipse的调试器通常只显示参数" arg1"," arg2"等等)。 / p>
您可以尝试编写java代理并使用instrumentation API。要开始使用,您可以查看以下文章:http://blog.javabenchmark.org/2013/05/java-instrumentation-tutorial.html。 Julien Poaletti并没有尝试读变量,但我想你可以建立他的榜样。
但同样,使用自定义代理并不是运营部门应该允许的。使用风险自负!