从同一 class 中的其他方法更改 java 方法内部变量值
Change java method inner variables value from other methods in the same class
这是一道面试题。
问题:
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);
}
}
并且我们可以覆盖函数print。在函数'方法中。等...
所以,我的问题是:
为什么a.getClass().getDeclaredField("value")
可以从方法main中获取变量“a”?我在调试模式下检查了a.getClass().getDeclaredFields
返回数组的每一项,但没有发现任何规律。
a.getClass().getDeclaredFields
返回数组的每一项含义是否有任何引用。
我知道方法的内部变量保存在堆栈内存中,并在同一个线程中共享。我们可以通过反射或使用新的 Java 类加载器更改变量 main 的“a”值吗?
解决方案是一个很大的伪装。它根本不会改变 main
方法的变量。请注意,它还将问题的方法声明从 void method(int a,int b)
更改为 void method(Integer a, Integer b)
(我不确定解决方案是否允许这样做),以强制从 int
到 Integer
. (它还添加了原始代码中没有的 throws Exception
声明)。
因此,a.getClass().getDeclaredField("value")
表达式不会访问 main
方法中的任何内容,而是访问包装器 class java.lang.Integer
的 value
字段。然后,访问覆盖用于修改value
字段。
但请注意,这个讨厌的 hack 仍然对 main
方法没有影响。由于 main 方法使用 int
基元,因此这些值不受 java.lang.Integer
实例的任何操作的影响。这就是解决方案使用另一个技巧的原因——它使用 lines
来打印自己
System.out.println("a = " + a);
和
System.out.println("b = " + b);
其次是
System.exit(0);
由于 这些 打印语句正在使用 Integer
对象,它们受到黑客攻击的影响,而 System.exit(0)
调用确保该方法永远不会 returns 到 main
方法,因此永远不会执行 main
方法的打印语句。
一旦您理解了“自己打印并退出 JVM”部分,您就会认识到整个 Reflection hack 是完全没有必要的。您可以使用
实现完全相同的效果
public static void method(int a, int b) {
System.out.println("a = 100");
System.out.println("b = 200");
System.exit(0);
}
这与解决方案完全相同,甚至不需要更改问题的方法签名。但是,当然,如果没有分散注意力的 Reflection hack,实际发生的事情会更加明显。
也就是说,反射不提供任何访问局部变量的方法。为此,您需要一个调试器。由于您还要求 ClassLoader
,您可以操纵 class 的代码以使用不同的值,但这不能满足在 method
内执行此操作的问题要求,即而有问题的代码已经是 运行.
这是一道面试题。
问题:
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);
}
}
并且我们可以覆盖函数print。在函数'方法中。等...
所以,我的问题是:
为什么
a.getClass().getDeclaredField("value")
可以从方法main中获取变量“a”?我在调试模式下检查了a.getClass().getDeclaredFields
返回数组的每一项,但没有发现任何规律。a.getClass().getDeclaredFields
返回数组的每一项含义是否有任何引用。我知道方法的内部变量保存在堆栈内存中,并在同一个线程中共享。我们可以通过反射或使用新的 Java 类加载器更改变量 main 的“a”值吗?
解决方案是一个很大的伪装。它根本不会改变 main
方法的变量。请注意,它还将问题的方法声明从 void method(int a,int b)
更改为 void method(Integer a, Integer b)
(我不确定解决方案是否允许这样做),以强制从 int
到 Integer
. (它还添加了原始代码中没有的 throws Exception
声明)。
因此,a.getClass().getDeclaredField("value")
表达式不会访问 main
方法中的任何内容,而是访问包装器 class java.lang.Integer
的 value
字段。然后,访问覆盖用于修改value
字段。
但请注意,这个讨厌的 hack 仍然对 main
方法没有影响。由于 main 方法使用 int
基元,因此这些值不受 java.lang.Integer
实例的任何操作的影响。这就是解决方案使用另一个技巧的原因——它使用 lines
System.out.println("a = " + a);
和
System.out.println("b = " + b);
其次是
System.exit(0);
由于 这些 打印语句正在使用 Integer
对象,它们受到黑客攻击的影响,而 System.exit(0)
调用确保该方法永远不会 returns 到 main
方法,因此永远不会执行 main
方法的打印语句。
一旦您理解了“自己打印并退出 JVM”部分,您就会认识到整个 Reflection hack 是完全没有必要的。您可以使用
实现完全相同的效果public static void method(int a, int b) {
System.out.println("a = 100");
System.out.println("b = 200");
System.exit(0);
}
这与解决方案完全相同,甚至不需要更改问题的方法签名。但是,当然,如果没有分散注意力的 Reflection hack,实际发生的事情会更加明显。
也就是说,反射不提供任何访问局部变量的方法。为此,您需要一个调试器。由于您还要求 ClassLoader
,您可以操纵 class 的代码以使用不同的值,但这不能满足在 method
内执行此操作的问题要求,即而有问题的代码已经是 运行.