从同一 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。在函数'方法中。等...

所以,我的问题是:

  1. 为什么a.getClass().getDeclaredField("value")可以从方法main中获取变量“a”?我在调试模式下检查了a.getClass().getDeclaredFields返回数组的每一项,但没有发现任何规律。 a.getClass().getDeclaredFields返回数组的每一项含义是否有任何引用。

  2. 我知道方法的内部变量保存在堆栈内存中,并在同一个线程中共享。我们可以通过反射或使用新的 Java 类加载器更改变量 main 的“a”值吗?

解决方案是一个很大的伪装。它根本不会改变 main 方法的变量。请注意,它还将问题的方法声明从 void method(int a,int b) 更改为 void method(Integer a, Integer b) (我不确定解决方案是否允许这样做),以强制从 intInteger. (它还添加了原始代码中没有的 throws Exception 声明)。

因此,a.getClass().getDeclaredField("value") 表达式不会访问 main 方法中的任何内容,而是访问包装器 class java.lang.Integervalue 字段。然后,访问覆盖用于修改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 内执行此操作的问题要求,即而有问题的代码已经是 运行.