枚举是否可以为其每个常量都有一个构造函数

Can an enum have a constructors for each of its constants

请看这个link。 Joshua Bloch 在他的著作 Effective Java 中说

请注意,操作常量是从一个 创建常量后 运行s 的静态块。

Trying to make each constant put itself into the map from its own constructor would cause a compilation error

。这是一件好事,因为它会导致 NullPointerException 如果它是合法的。

Enum constructors aren’t permitted to access the enum’s static fields, except for compile-time constant fields.

这个限制是必要的 因为构造函数运行.

时这些静态字段还没有初始化

我有两个问题

  1. 枚举可以为每个常量提供单独的构造函数吗?
  2. 为什么编译时常量字段可在构造函数中访问,但静态字段不可访问?

谢谢

  1. 不,我不认为那是 Bloch 的意思,尽管它没有以最好的方式表述。 enum 可以有构造函数,就像书中的 enum Operation 一样。 Bloch 对 "its own constructor" 的意思是:当 Operation 的构造函数针对特定常量运行时。

  2. 上面引用的内容已经回答了这个问题:

    This restriction is necessary because these static fields have not yet been initialized when the constructors run.

关于第一个问题:你不能有单独的构造函数,但你可以通过以下方式解决这个问题:

public enum EnumTest {
    ONE() {
        void init() {
            val = 2;
        }
    },
    TWO() {
        void init() {
            val = 1;
        }
    };

    protected int val;

    abstract void init();

    EnumTest() {
        init();
    }
}

从技术上讲,这样您就可以为不同的常量提供单独的初始化方法。

另一种方法是使用初始化部分:

public enum EnumTest {
    ONE() {{
            val = 2;
        }},
    TWO() {{
            val = 1;
        }};

    protected int val;
}

关于你的第二个问题:在枚举构造过程中,常量字段是不可访问的,因为枚举常量是静态字段可以访问的。例如,这段代码编译正确:

public enum EnumTest {
    ONE, TWO;

    public static final String ONE_STRING = ONE.toString();
}

如果允许从构造函数访问 ONE_STRING,您将面临无限的初始化循环或访问尚未初始化的枚举常量。

构造函数的常规规则适用。您可以拥有任意数量的构造函数,只要它们具有不同的签名即可。然后可以使用不同的构造函数构建不同的 enum 值:

enum StringAndNumber {
    Zero("zero"),
    Five(5),
    Pi("Pi", 3.14159);

    private final String str;
    private final Number num;

    private StringAndNumber(String str) {
        this.str = str;
        this.num = null;
    }

    private StringAndNumber(Number num) {
        this.num = num;
        this.str = null;
    }       

    private StringAndNumber(String str, Number num) {
        this.str = str;
        this.num = num;
    }
}