资源文件中的最终变量

2024-02-26

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

问题:

如果我直接在实例化时分配它们(如下所示):

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()).

如果我想在活动的 onCreate() 方法中分配值,我会收到错误Cannot assign value to final variable 'PREFERENCE_NAME'

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

提前致谢。


简单的答案是你不能。

声明的变量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存在阻止你这样做),但你不应该这样做,因为它可能会产生非常非常奇怪的副作用。

如果您真的决定实施此操作,如果您的房子出现白蚁或您的猫着火,我不承担任何责任。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

资源文件中的最终变量 的相关文章

  • 自动检测log4j静态初始化错误的方法

    请注意 这更像是 Bash 问题 而不是 Java 问题 请参阅下面的注释 在每个类中配置log4j时 我们执行以下操作 public class Example private static final Logger log Logger
  • 如何在生产中安全地更改会话 cookie 域或名称?

    我们最近意识到我们的会话 cookie 正在被写入我们网站的完全限定域名 www myapp com 例如 MYAPPCOOKIE 79D5DB83 domain www myapp com 我们希望将其切换为可以跨子域共享的cookie
  • Kotlin 协程阻塞 Android 中的主线程

    我是 Kotlin 和协程的新手 我有一个fun在我的活动及其内部 检查User用户名和密码 如果为真 则返回Users object 一切都好 但是当我按下按钮时 我的活动被阻止并等待响应Users login 我用这个有趣的 priva
  • 改造添加带有令牌和 ID 的标头

    我在获取经过身份验证的用户时遇到问题 在此之前我得到了令牌和用户 ID 现在我需要使用访问令牌和 ID 从服务器获取用户 我有标题格式 https i stack imgur com OQ87Y png 现在我尝试使用拦截器添加带有用户令牌
  • setOnTouchListener() 给我一个错误

    button setOnTouchListener new OnTouchListener public void onClick View v Toast makeText MainActivity this YOUR TEXT 5000
  • 飞碟中的外部 CSS

    我想知道如何在 Flying Saucer 中包含外部 CSS 在此之前THB我检查了所有可用的链接StackOverflow但它们没有帮助 这就是为什么我自己做这个的原因 TestCSS xhtml重命名版本TestCSS html 所以
  • Android 改造参数化@Headers

    我正在使用 OAuth 每次发出请求时都需要将 OAuth 令牌放入标头中 我看到 Header注释 但是有没有办法让它参数化 以便我可以在运行时传入 这是概念 Header Authorization OAuth var api vers
  • Spring-data-cassandra:创建名称为“sessionFactory”的 bean 时出错,并且无法解析对 bean“cassandraTemplate”的引用

    我有一个 springboot 应用程序 在其中连接到 cassandra DB 我的 pom xml parent gt
  • Android Studio 3.0 - 设置未保存

    我已将 文件 gt 设置 gt 编辑器 gt 代码样式 中的 右边距 列 从默认的 100 增加到 140 不幸的是 每次重新启动 Android Studio 后 该边距都会重置 我还尝试导出和导入我的设置 但这并不能阻止重置右边距 希望
  • 如何知道一个点是否在复杂的 3D 形状内(.ply 文件)

    我正在研究一个Java女巫项目真是要了我的命 经过几天在不同论坛上的研究 寻找我真正需要的东西 我来寻求你的帮助 我的数据 ply 文件 包含由许多三角形组成的 3D 形状 一个点 3D坐标 我想知道这个点是否包含在复杂的 3D 形状内 我
  • 重构 google 的 NetworkBoundResource 类以使用 RxJava 而不是 LiveData

    谷歌的android架构组件教程here https developer android com topic libraries architecture guide html有一部分解释了如何抽象通过网络获取数据的逻辑 在其中 他们使用
  • 表达式的类型必须是数组类型,但它解析为浮点数

    当我编写 Java 代码时 我遇到了困难 我觉得我不知何故把这个概念弄乱了 就像我不确定这一点 void setScore float sco sco score public void setScore float sco int id
  • 什么是“多重”启动模式?

    On http developer android com guide topics manifest activity element html http developer android com guide topics manife
  • 设置 LinearLayout 的最大宽度

    如何设置水平线的最大宽度LinearLayout 因此 如果内容较短 例如某些文本 布局会缩小 如果内容较长 则布局不会扩展超过某个最大宽度值 我更喜欢在 XML 级别执行此操作 这就是我所需要的超出了之前答案中的建议 https stac
  • Android:列表视图崩溃

    我正在使用 android listview 并且它工作得很好 我的实现如下 ListView listview ListView findViewById R id list setListAdapter new ArrayAdapter
  • 如何创建克隆重复视图?

    在我的 Android 应用程序中 我想创建重复的ImageButton已经创建的Imagebutton 我想创造新的Imagebutton以编程方式与 XML 文件中已创建的按钮具有相同的宽度 高度 背景 图像源 边距等 简而言之 我想创
  • Android 预安装检测

    我的 Android 应用程序将被预安装 我想继续跟踪预安装的应用程序 为此 我需要以某种方式保存密钥或标志 这意味着该应用程序是预安装的 我会将此密钥添加到后端的每个请求中并对其进行分析 我对此有疑问 有一个问题是关于从 Google P
  • JAXB 枚举字段未序列化

    我有以下课程 package dictionary import java io Serializable import java util Objects import javax xml bind annotation XmlEleme
  • 如何在给定的纬度和经度处使用标记/覆盖项目启动地图意图?

    我有一个纬度和经度 我想打开以该点为中心的谷歌地图 所以我使用以下代码 Intent intent new Intent android content Intent ACTION VIEW Uri parse geo lat lng st
  • Android,Volley请求,响应阻塞主线程

    使用 Volley 处理较大响应时会发生一些不好的事情 String url AppHelper DOMAIN service pages profile update json this infoTextView setText getS

随机推荐