gpt4 book ai didi

java - 资源文件中的最终变量

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:52:56 24 4
gpt4 key购买 nike

我有一个包含一些final 变量的 Activity 。我将它们的值(假设它们都是字符串)提取到一个资源文件中。

问题:

如果我在实例化时直接赋值(如下):

private final String PREFERENCE_NAME = getResources().getString(R.string.preference_name);

我收到以下错误:

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference

我明白这个问题; onCreate() 方法尚未被调用,这意味着我无法访问与上下文相关的方法 (getResources())。

如果我想在 Activity 的 onCreate() 方法中赋值,我会得到错误 Cannot assign value to final variable 'PREFERENCE_NAME'

问题是:如何从资源文件中获取最终变量?如果这不可能,解决方案的最佳实践是什么?

提前致谢。

最佳答案

简单的答案是你不能。

声明为 final 的变量只能在实例化对象时设置(即在构造函数中或使用初始化代码)。

一直使用 getResources().getString(R.string.preference_name); 或使用非最终变量。

复杂的答案是您可以但不应该。

当您声明变量 final 时,编译器和 VM 使用它来进行优化和假设。它可以这样做是因为变量保证永远不会改变。在初始化后更改它可能会导致非常奇怪的错误,因此您绝对不应该这样做。

这是你如何做的:

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

这将输出:

Hello World!
Hello Mars!

太好了,所以我们更改了一个 final 变量。没问题吧?

好吧,改用这个例子:

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

这将输出:

Hello World!
Hello World!

等等,什么?

问题是编译器可以看到变量 message 总是 "Hello World!" 所以它内联 "Hello World!" 而不是我们对 f.getMessage() 的调用。如果您在调试器中运行它,您将看到调试器将实例中的更新消息反射(reflect)到 "Hello Mars!" 但由于该变量实际上从未被访问过,因此不会影响程序的结果.

总结一下:您可以通过反射更新 final 字段(假设没有 Security Manager 阻止您这样做),但您不应该这样做,因为它会产生非常非常奇怪的副作用。

如果您真的决定实现此功能,如果您的房子有白蚁或您的猫着火,我概不负责。

关于java - 资源文件中的最终变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29913722/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com