java中的静态块如何工作?

kev*_*rch 1 java static-methods

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

像这样:

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

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

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

它无法按预期编译。

但是,如果我这样写。

static {
    map = new HashMap<>();
}
private static Map<String, Object> map;
Run Code Online (Sandbox Code Playgroud)

就顺利通过了?!有人知道发生了什么事吗?它不介意我是否为map分配一个新对象,但如果我在地图上放置一些东西,它就无法编译。

请给我一个合理的答案。

Swe*_*per 5

mapJava 语言规范中提到了禁止在静态初始化程序中使用 的基本原理:

\n

\xc2\xa712.4.1 :

\n
\n

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

\n
\n

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

\n

另一方面,如果您map = new HashMap<>();在静态初始化程序中执行了操作,那么您只是在初始化 map。那里没有什么问题!请注意,从上到下处理的是变量初始值设定项( 后面的内容)。=您始终可以看到前面以文本方式声明的声明,只要它们在范围内即可。在这两种情况下, 的字段声明map都在范围内。

\n

\xc2\xa78.3.3中进一步指定了允许和不允许的精确规则:

\n
\n

其声明在使用后以文本形式出现的类变量的使用有时会受到限制,即使这些类变量在作用域内。具体来说,如果满足以下所有条件,则为编译时错误:

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

    \n
  • \n
  • 在 C 的类变量初始值设定项或 C 的静态初始值设定项中使用简单名称;

    \n
  • \n
  • 使用不在作业的左侧;

    \n
  • \n
  • C 是封闭使用的最内部类或接口。

    \n
  • \n
\n
\n

注意第三点——只有不在LHS上使用才是错误!

\n