【问题标题】:Static variable not initialized when class is loaded加载类时未初始化静态变量
【发布时间】:2012-06-15 23:02:29
【问题描述】:

我有一个关于初始化的有趣问题。我有以下代码:

public class ErrorLookupProvider {  

private static final ErrorLookupProvider INSTANCE = new ErrorLookupProvider();

private  static Map<Long, List<String>> map = new HashMap<Long, List<String>>();

    private ErrorLookupProvider() {
        init();
    }

    private void init() {
        map.put(123L, ImmutableList.of("abc", "def"));
    }

    public static ErrorLookupProvider getInstance() {
        return INSTANCE;
    }
}

现在当我打电话给ErrorLookupProvider.getInstance() 时,我遇到了 NPE。 init() 内部的映射没有用新的HashMap 初始化。

如果我将map 的声明更改为最终声明,那么我看到它已初始化。或者,即使我删除了 static 并将其设置为 private Map&lt;.....&gt; 的私有类变量也可以。

我无法弄清楚为什么会发生这种情况。有人可以解释这里发生了什么吗?

【问题讨论】:

  • 即使使用非长映射键也能编译吗?
  • 我错了,我错过了 123L

标签: java initialization static-members


【解决方案1】:

切换地图和单例实例初始化的顺序。

静态初始化按照它在源中遇到的顺序发生。

参见JLS 12.4.2 Detailed Initialization Procedure,步骤 6(final 部分)和 9(“订单”部分)。

(单例实现和 ctor 中的静态处理,单独的问题。)

【讨论】:

  • 哦!那是因为静力学的顺序。如果我把地图放在第一位,我想就可以了。这让我想到了一个问题——这是否允许?私有静态最终 ErrorLookupProvider INSTANCE = new ErrorLookupProvider();按照顺序,我通过调用构造函数来初始化我的静态变量。这意味着甚至在变量初始化之前就调用了构造函数。那么这种用法不正确吗?通常,初始化发生如下: 1. 静态成员 2. 静态块 3. 成员变量 4. 构造函数 现在,我正在尝试从 1 跳转到 4。应该禁止这样做吗?
  • @Sudoer 是的,这就是我们所说的——订单很重要 :) 当然是允许的——它有效,不是吗?
【解决方案2】:

引用http://javapapers.com/core-java/explain-the-final-keyword-in-java/

声明为 final 且未初始化的变量称为空白 final 变量。一个空白的 final 变量会强制构造函数对其进行初始化。

这就是为什么当声明为 final 时它会被初始化

【讨论】:

  • 调用 private static final ErrorLookupProvider INSTANCE = new ErrorLookupProvider() 是否有效?类初始化首先是静态变量、静态块、成员变量,然后是构造函数。但是,在这种情况下,调用构造函数初始化静态变量是否有效?
  • 是的,那很好。只是对您的代码的一个小评论,您可以将这个私有静态 Map> map = new HashMap(); 用作 HashMap 的声明
  • NO NO NO,当声明为final时,如果变量没有被你初始化,构造函数将强制它被初始化
  • @MaVRoSCy 新的更短的语法很好,但只适用于 Java 7。
【解决方案3】:

添加:订单很重要。将静态地图的声明放在 INSTANCE 的声明之前。 Java 编译器对排序有点傻……

由于地图是静态的,它在ErrorLookupProvider 的所有实例之间共享。因此,在构造函数中使用它可能是一个错误。如果您创建多个 ErrorLookupProviders,您将多次冗余添加到地图中。相反,在静态初始化块中初始化它。或者,如果它确实意味着在 ErrorLookupProvider 的实例之间是独立的,请不要将其设为静态。

【讨论】:

    猜你喜欢
    • 2010-09-26
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 2017-07-22
    • 1970-01-01
    • 2020-12-11
    相关资源
    最近更新 更多