问题:
public class test {
public static void main(String[] args) {
int a= 10;
int b=10;
method(a,b);
System.out.println(a);
System.out.println(b);
}
public static void method(int a,int b){
//**Under the premise of not changing the original question, how to write this function in the main function to output a=100,b=200?**
}
}
数目:
import java.lang.reflect.Field;
class Text
{
public static void main(String[] args) throws Exception
{
int a = 10;
int b = 10;
method(a,b);
System.out.println("a = " + a);
System.out.println("b = " + b);
}
private static void method(Integer a, Integer b) throws Exception
{
Field fielda = a.getClass().getDeclaredField("value");
fielda.setAccessible(true);
fielda.set(a,100);
System.out.println("a = " + a);
Field fieldb = b.getClass().getDeclaredField("value");
fieldb.setAccessible(true);
fieldb.set(b,200);
System.out.println("b = " + b);
System.exit(0);
}
}
我们可以覆盖功能打印。在功能'方法。等...
为什么a.getClass().getDeclaredField("value")
可以从方法main获得变量“a”?我在调试模式下检查了a.getClass().getDeclaredFields
返回的数组的每个项目,但没有找到任何规律性。
是否有关于a.getClass().getDeclaredFields
返回数组的每个项目含义的任何引用。
我知道方法的内部变量保存在堆栈内存中,并在同一个线程中共享。我们可以通过Reflection或使用新的Java类加载器来更改变量main的“a”值吗?
答案 0 :(得分:0)
解决方案是一个很大的伪装。它根本不会改变void method(Integer a, Integer b)
方法的变量。请注意,它还将问题的方法声明从int
更改为Integer
(我不确定这是否允许解决方案),以强制执行从throws Exception
到{{1}的装箱转换}}。 (它还添加了原始代码中没有的a.getClass().getDeclaredField("value")
声明。
因此,main
表达式不会访问value
方法中的任何内容,而是访问包装类java.lang.Integer
的{{1}}字段。然后,访问覆盖用于修改value
字段。
但请注意,这个令人讨厌的黑客仍然对main
方法没有影响。由于main方法使用int
原语,因此这些值不受java.lang.Integer
实例的任何操作的影响。这就是解决方案使用另一种技巧的原因 - 它使用行
System.out.println("a = " + a);
和
System.out.println("b = " + b);
接着是
System.exit(0);
由于这些打印语句正在使用Integer
对象,因此它们受到黑客的影响,而System.exit(0)
调用确保方法永远不会返回{{1方法,因此永远不会执行main
方法的print语句。
一旦你理解了“自己打印并退出JVM”部分,你就会认识到整个Reflection hack是完全没必要的。您可以使用
完全相同main
这与解决方案完全相同,甚至不需要更改问题的方法签名。但是,当然,如果没有分散注意力的反射黑客,那么实际发生的事情就更明显了。
也就是说,Reflection没有提供任何访问局部变量的方法。你需要一个调试器。由于您还要求public static void method(int a, int b) {
System.out.println("a = 100");
System.out.println("b = 200");
System.exit(0);
}
,您可以操纵类的代码以使用不同的值,但这不符合在ClassLoader
内执行此操作的问题,即在代码中问题已在运行。