java - 静态初始值设定项不能在定义之前引用字段

标签 java static-initialization static-initializer

我有以下代码,错误已注释

public final class MyStaticClass {

    private MyStaticClass() {}

    static {

        a = new A();
        b = new B(a);    // Cannot access a field before it is defined
    }

    private static final A a;
    private static final B b;
}

我对使用静态初始值设定项还很陌生,但我不知道为什么不能编译。我浏览了一些关于这个主题的帖子,并且看到了初始化运行的顺序,但这似乎并不违反规则。当 b 被初始化时,a 应该已经被初始化了。

我有一个变通办法,就是将此类设置为单例,但这样做会降低代码的可读性。我很想知道这里出了什么问题。

最佳答案

这在 JLS 8.3.3 中有解释.事实上,有几种方法可以修复它。

使用限定名称a:

// #1
public final class MyStaticClass {
    static {
        a = new A();
        b = new B(MyStaticClass.a);
    }

    private static final A a;
    private static final B b;
}

如果 ab 是在实例初始化程序中初始化的实例字段,则 a 可以限定为 this.a.

将对 a 的前向引用放在赋值的左侧:

// #2
public final class MyStaticClass {
    static {
        b = new B(a = new A());
    }

    private static final A a;
    private static final B b;
}

当然,将声明以文本形式放在引用之前:

// #3
public final class MyStaticClass {
    private static final A a;
    private static final B b;

    static {
        a = new A();
        b = new B(a);
    }
}

根据 JLS,#3 在技术上不是必需的(“这些类变量在范围内”),而是旨在捕获一种特殊类型的错误,其中字段初始化顺序不正确:

public final class MyStaticClass {
    private static final B b = new B(a); // a is null
    private static final A a = new A();
}

(尽管我只是向您展示了两种方法来阻止它并无论如何都会犯错误。)

我推荐 #1 或 #3,因为 #2 有点深奥。您似乎没有犯此规则旨在捕获的错误。

关于java - 静态初始值设定项不能在定义之前引用字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26784924/

相关文章:

c# - C# 中的集合初始化器

java - synchronized(){} 的异步(非阻塞)版本

c++ - 对象构造/初始化的顺序

java - 静态和非静态初始化代码块有什么区别

java - 最终定义不明确吗?

c++ - 当我通过静态函数访问静态成员时,是否会出现静态初始化顺序失败的情况?

java - 为什么静态初始化程序允许在 Java 中重新初始化静态变量?

java - 文本搜索的运行时间非常慢 [优化]

java - Android Retrofit错误需要HTTP方法注解(例如@GET、@POST等)

java - 尝试读取系统提供给我的 listFiles 时出现 FileNotFoundException。这是名称编码问题吗?