Field.class.getDeclaredField不更改静态字段的值

时间:2016-06-05 15:13:05

标签: java junit

这是我的班级

public final class MyAPIKey {

    private MyAPIKey(){

    }

    public static final String APIKey = "xxxxx";

}

我用它来修改我的juni的api键

 import java.lang.reflect.*;

import com.search.externalcalls.MyAPIKey;

public class EverythingIsTrue {
   static void setFinalStatic(Field field, Object newValue) throws Exception {
      field.setAccessible(true);

      Field modifiersField = Field.class.getDeclaredField("modifiers");
      modifiersField.setAccessible(true);
      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

      field.set(null, newValue);
   }
   public static void main(String args[]) throws Exception {      
      setFinalStatic(Boolean.class.getDeclaredField("FALSE"), true);

      System.out.format("Everything is %s", Boolean.FALSE); // "Everything is true"

      setFinalStatic(MyAPIKey.class.getDeclaredField( "APIKey" ), "asdads");
      System.out.println();
      System.out.format("Everything is %s", MyAPIKey.APIKey); // "Everything is asdads"
   }
}

问题是布尔值正在改变但是我的变量的值不能帮助我弄清楚为什么会发生这种情况?

3 个答案:

答案 0 :(得分:1)

编译器可以自由地用它们的实际值替换常量出现而不是对它们的字段的引用。例如:

private static final String VALUE = "value".

public void test() {
  System.out.println("Some " + VALUE + ".");
}

此方法调用也可以编译为System.out.println("Some value."),这是更便宜的"在运行时,因为它不需要字符串构建。这就是为什么你通常用反射修改常量。

答案 1 :(得分:0)

好的找到了解决方案。虽然不确定为什么会这样。但是如果你声明一个静态内联它就行不通。你可以使用一个简单的getter然后它就可以改变。必须是编译器的一些不好的东西,否则我可能完全走错了方向。

public final class myAPIKey {

    private myAPIKey(){

    }

    public static final String APIKey = getAPIKey();

    private static String getAPIKey() {
        return "xxxx";
    }


}

虽然可能有更好的解决方案,但这对我有用

答案 2 :(得分:0)

提示:不要这样做:不要狂暴使用反射,以使您的设计可测试。

相反:将生产代码更改为可测试。

我的意思是:如果你真的需要能够改变一个" init"您的类的值,然后考虑使用依赖注入将该值传入您的类。其中:最有可能的是,您的真正问题是其他代码在myAPIKey类上使用这些静态方法;当然,这会导致各种各样的问题...作为一个很好的例子,为什么应该避免静态,因为它可以使您的设计无法快速测试。

所以,而不是一个"隐含的"您调用静态方法的myAPIKey单例;你只需传递普通的myAPIKey个对象;没有静态方法;然后可以使用EasyMock进行模拟(例如:你需要" un-final"你的类才能在这里使用EasyMock。)

如果我无法说服你改变你的生产代码......至少:不要自己这样做。像它们一样丑陋和危险,有像PowerMock这样的框架允许你做出这样的"覆盖"用于检测。无需重新发明轮子。

但是如上所述:你将要走的道路将导致痛苦。现在更好的转身,并提高您的设计质量!因为"难以测试"直接翻译为"设计需求改进"。

此外:类名应始终以Java中的大写字母开头。