简单的答案是你不能。
声明的变量final
只能在实例化对象时设置(即在构造函数中或使用初始化代码)。
要么使用getResources().getString(R.string.preference_name);
始终或使用非最终变量。
复杂的答案是你可以,但你不应该。
当你声明一个变量时final
编译器和虚拟机使用它来进行优化和假设。它可以做到这一点,因为变量保证永远不会改变。在初始化后更改它可能会导致非常奇怪的错误,所以你绝对不应该这样做。
操作方法如下:
public class FinalMessage {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
FinalMessage f = new FinalMessage("Hello World!");
System.out.println(f.getMessage());
f.changeFinalMessage("Hello Mars!");
System.out.println(f.getMessage());
}
private final String message;
public FinalMessage(String message) {
this.message = message;
}
void changeFinalMessage(String newMessage) throws IllegalAccessException, NoSuchFieldException {
final Field field = FinalMessage.class.getDeclaredField("message");
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(this, newMessage);
}
String getMessage() {
return message;
}
}
这将输出:
你好世界!
你好火星!
太好了,所以我们改变了最终变量。没问题吧?
好吧,以这个例子为例:
public class FinalMessage {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
FinalMessage f = new FinalMessage();
System.out.println(f.getMessage());
f.changeFinalMessage("Hello Mars!");
System.out.println(f.getMessage());
}
private final String message = "Hello World!";
void changeFinalMessage(String newMessage) throws IllegalAccessException, NoSuchFieldException {
final Field field = FinalMessage.class.getDeclaredField("message");
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(this, newMessage);
}
String getMessage() {
return message;
}
}
这将输出:
你好世界!
你好世界!
等等,什么?
问题是编译器可以看到变量message
永远都会是"Hello World!"
所以它内联"Hello World!"
而不是我们的电话f.getMessage()
。如果您在调试器中运行此命令,您将看到调试器将实例中更新的消息反映为"Hello Mars!"
但由于该变量实际上从未被访问过,因此不会影响程序的结果。
总结一下:您可以通过反射更新最终字段(假设没有安全经理 https://docs.oracle.com/javase/tutorial/essential/environment/security.html存在阻止你这样做),但你不应该这样做,因为它可能会产生非常非常奇怪的副作用。
如果您真的决定实施此操作,如果您的房子出现白蚁或您的猫着火,我不承担任何责任。