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"
}
}
问题是布尔值正在改变,而不是变量的值。有人能帮我弄清楚为什么会发生这种情况吗
# 1 楼答案
编译器可以自由地将常量引用替换为其实际值,而不是对其字段的引用。例如:
这个方法调用也可以编译成
System.out.println("Some value.")
,这在运行时“更便宜”,因为它不需要构建字符串。这就是为什么您通常应该而不是使用反射修改常量的原因# 2 楼答案
提示:不要这样做:不要使用反射来使您的设计可测试
相反:将生产代码更改为可测试的
我的意思是:如果你真的需要改变你的类的“init”值,那么考虑使用依赖注入来获得这个值到你的类中。其中:最有可能的是,您真正的问题是其他代码正在
myAPIKey
类上使用这些静态方法;当然,这会导致各种各样的问题。。。这是一个很好的例子,说明为什么应该避免使用静态,因为它会使您的设计很快变得不可测试因此,不要使用“隐式”
myAPIKey
单例来调用静态方法;只需传递普通的myAPIKey
对象;没有静态方法;然后可以使用EasyMock来模拟(其中:为了在这里使用EasyMock,您必须“取消最终”类)如果我不能说服你改变你的生产代码。。。至少:不要自己做这件事。尽管它们丑陋而危险,但有一些像PowerMock这样的框架允许您进行此类“覆盖”测试。不需要重新发明轮子
但正如所说:你将要走的道路将导致痛苦。最好现在就回头,提高你的设计质量!因为“难以测试”直接转化为“设计需要改进”
此外:在Java中,类名应始终以大写字母开头
# 3 楼答案
Ok找到了解决办法。虽然不知道为什么会发生这种情况。但是,如果您声明一个静态内联,它将不起作用。您可以使用一个简单的getter,然后它就可以更改了。一定是一些不可靠的东西与编译器,否则我可能会在错误的方向上完全
这对我来说很有效,尽管可能有更好的解决办法