1

假设,我希望枚举的所有实例共享一个 int[] 数组。这是一个例子

public enum SampleEnum {
    Enum1(1), Enum2(2), Enum3(3), Enum4(4);

    private int[] values;

    private static final int[] SharedValues = {1, 2, 3, 4, 5};
    private static final int ValueCount = SharedValues.length;

    private SampleEnum(int factor) {
        // I prefer to calculate data once within constructor
        values = new int[ValueCount];
        for (int i=0; i<ValueCount; i++)
            values[i] = SharedValues[i] * factor;
    }

    private int[] getValues() {
       return values;
    }    
}

猜猜看:对于 ValueCount 和 SharedValues,我收到消息“无法引用初始化程序中的静态枚举字段”。

这个问题可以通过将静态数组放在一个单独的类中来解决:

class SampleEnumData {
    static final int[] SharedValues = {1, 2, 3, 4, 5};
}


public enum SampleEnum {
    Enum1(1), Enum2(2), Enum3(3), Enum4(4);

    private int[] values;

    private SampleEnum(int factor) {
        // I prefer to calculate data once within constructor
        int[] sharedValues = SampleEnumData.SharedValues;
        int valueCount = sharedValues.length;
        values = new int[valueCount];
        for (int i=0; i<valueCount; i++)
            values[i] = sharedValues[i] * factor;
    }

    private int[] getValues() {
       return values;
    }    
}

但这看起来更像是一个尴尬的补丁,而不是一个合乎逻辑的解决方案。

是否有理由不允许在枚举初始化程序中引用静态类?

4

2 回答 2

3

是否有理由不允许在枚举初始化程序中引用静态类?

这是一个不允许您访问的静态字段,并且有一个很好的理由:该字段仍将具有其初始值,因为枚举成员将在任何以后的静态字段初始化程序之前初始化。如果您尝试填充由枚举的某些方面键控的映射,这通常是一个问题 - 您真的很想在构造函数中执行填充,但您不能因为映射尚未创建。

选项:

  • values在构造所有实例后执行的静态初始化程序块中执行所有初始化。这里的问题是,如果您希望该字段成为最终字段,则需要先创建数组,这意味着知道要创建多大的数组,而无需访问数据。(您在这里选择的名字很不幸,因为这里values()也提供了方法,请注意。)
  • 使用私有嵌套类作为静态字段初始化的“持有者”。这就像您的第二个解决方案,但没有暴露课程。

老实说,后一种方法可能是最简单的。

public enum SampleEnum {
    ...

    private static class SampleEnumData {
        static final int[] SHARED_VALUES = {1, 2, 3, 4, 5};
    }
}
于 2013-10-21T06:06:22.437 回答
0

只是想提供另一个例子。我试图创建一个偏移量/长度的字段字典,以保证名称的唯一性,并且对移动字段、在中间添加新字段等具有弹性。

我在尝试像这样引用偏移量时遇到了这个“无法访问静态字段”:

    enum Fields1 {
        FIELD1(4), FIELD2(1), FIELD3(8), FIELD4(8);        

        private static int nextOfs = 0;

        public final int size;
        public final int offset;

        private Fields1(int size) {
            this.size = size;
            this.offset = nextOfs;  // Cannot refer to the static enum field Fields1.nextOfs within an initializer
            nextOfs += size;        // Same here
        }
    }

在阅读了这篇文章及其答案后,我切换到了这个:

enum Fields {
    FIELD1(4), FIELD2(1), FIELD3(8), FIELD4(8);

    public final int size;
    public final int offset;

    private Fields(int size) {
        this.size = size;
        this.offset = OffsetAllocator.FieldsAllocator.getNextOfs(size);
    }

    private static final class OffsetAllocator {
        private static final OffsetAllocator FieldsAllocator = new OffsetAllocator();

        private int nextOfs = 0;

        private final int getNextOfs(int size) {
            int ofs = nextOfs;
            nextOfs += size;
            return ofs;
        }
    }
}
于 2016-10-05T13:44:43.290 回答