首页 > 解决方案 > java中的静态块如何工作?

问题描述

据我所知,静态字段和块是在一个类中从上到下处理的。我的意思是,必须先声明一个字段(静态字段),然后才能在静态块中使用它。必须首先声明静态字段,然后是修改该静态字段的静态块。正确的?

像这样:

private static Map<String, Object> map = new HashMap<>();
static {
    map.put("key", "value");
}

它编译。如果我们像这样颠倒顺序:

static {
    map.put("key", "value");
}
private static Map<String, Object> map = new HashMap<>();

它无法按预期编译。

但是,如果我这样写。

static {
    map = new HashMap<>();
}
private static Map<String, Object> map;

成功了?!有人知道发生了什么吗?如果我为map分配一个新对象并不介意,但是如果我在 map 上放一些东西,它就无法编译。

请给我一个合理的答案。

标签: javastatic-methods

解决方案


mapJava语言规范中提到了不允许在静态初始化程序中使用的理由:

§12.4.1

静态初始化器和类变量初始化器按文本顺序执行,并且不能引用在使用后以文本形式出现的类中声明的类变量,即使这些类变量在范围内。此限制旨在在编译时检测大多数循环或其他格式错误的初始化。

由于初始化程序以文本顺序运行,静态初始化程序将在 之前运行new HashMap<>(),因此在map.put执行map时,此时不会被初始化。显然,这是“畸形”。

另一方面,如果你map = new HashMap<>();在静态初始化器中做了,你只是在初始化 map。那里没有错!请注意,从上到下处理的是变量初始化程序(后面的东西)。只要它们在范围内=,您总是可以看到前面以文本形式声明的声明。的字段声明在这两种情况下都在范围内。map

§8.3.3进一步规定了允许和不允许的精确规则:

有时限制使用在使用后以文本形式出现声明的类变量,即使这些类变量在范围内。具体来说,如果以下所有条件都为真,则为编译时错误:

  • 类或接口 C 中的类变量声明在使用类变量之后以文本形式出现;

  • use 是 C 的类变量初始化器或 C 的静态初始化器中的简单名称;

  • 使用不在作业的左侧;

  • C 是包含使用的最内层类或接口。

注意第三点——只有在 LHS 上没有使用才会出错!


推荐阅读