有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java字段。班getDeclaredField不更改静态字段的值

这是我的课

public final class MyAPIKey {

    private MyAPIKey(){

    }

    public static final String APIKey = "xxxxx";

}

我使用它来修改junit的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) 个答案

  1. # 1 楼答案

    编译器可以自由地将常量引用替换为其实际值,而不是对其字段的引用。例如:

    private static final String VALUE = "value".
    
    public void test() {
      System.out.println("Some " + VALUE + ".");
    }
    

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

  2. # 2 楼答案

    提示:不要这样做:不要使用反射来使您的设计可测试

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

    我的意思是:如果你真的需要改变你的类的“init”值,那么考虑使用依赖注入来获得这个值到你的类中。其中:最有可能的是,您真正的问题是其他代码正在myAPIKey类上使用这些静态方法;当然,这会导致各种各样的问题。。。这是一个很好的例子,说明为什么应该避免使用静态,因为它会使您的设计很快变得不可测试

    因此,不要使用“隐式”myAPIKey单例来调用静态方法;只需传递普通的myAPIKey对象;没有静态方法;然后可以使用EasyMock来模拟(其中:为了在这里使用EasyMock,您必须“取消最终”类)

    如果我不能说服你改变你的生产代码。。。至少:不要自己做这件事。尽管它们丑陋而危险,但有一些像PowerMock这样的框架允许您进行此类“覆盖”测试。不需要重新发明轮子

    但正如所说:你将要走的道路将导致痛苦。最好现在就回头,提高你的设计质量!因为“难以测试”直接转化为“设计需要改进”

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

  3. # 3 楼答案

    Ok找到了解决办法。虽然不知道为什么会发生这种情况。但是,如果您声明一个静态内联,它将不起作用。您可以使用一个简单的getter,然后它就可以更改了。一定是一些不可靠的东西与编译器,否则我可能会在错误的方向上完全

    public final class myAPIKey {
    
        private myAPIKey(){
    
        }
    
        public static final String APIKey = getAPIKey();
    
        private static String getAPIKey() {
            return "xxxx";
        }
    
    
    }
    

    这对我来说很有效,尽管可能有更好的解决办法