从同一个类中的其他方法更改java方法内部变量值

时间:2017-02-21 03:44:39

标签: java reflection classloader

这是一个面试问题。

问题:

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);
  }
}

我们可以覆盖功能打印。在功能'方法。等...

所以,我的问题是:

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

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

1 个答案:

答案 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内执行此操作的问题,即在代码中问题已在运行。