Java 为enum-s提供公共数据的更好方法

Java 为enum-s提供公共数据的更好方法,java,enums,Java,Enums,假设,我希望一个int[]数组由enum的所有实例共享。这里有一个例子 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

假设,我希望一个int[]数组由enum的所有实例共享。这里有一个例子

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;
    }    
}
public enum SampleEnum{
枚举1(1)、枚举2(2)、枚举3(3)、枚举4(4);
私有int[]值;
私有静态final int[]SharedValue={1,2,3,4,5};
私有静态最终int-ValueCount=SharedValues.length;
私有样本数(整数因子){
//我更喜欢在构造函数中计算一次数据
值=新整数[ValueCount];
对于(int i=0;i
在枚举初始值设定项中不允许引用静态类有什么原因吗

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

选项:

  • 在静态初始化程序块中执行所有
    初始化,该初始化程序块在构建所有实例后执行。这里的问题是,如果希望字段为最终字段,则需要首先创建数组,这意味着知道数组的大小,而无需访问数据。(请注意,
    values()
    方法在这里也可用,因此您选择的名称在这里是不幸的。)
  • 使用私有嵌套类作为静态字段初始化的“持有者”。这类似于第二种解决方案,但不公开该类
老实说,后一种方法可能是最简单的

public enum SampleEnum {
    ...

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

只想提供另一个例子。我试图创建一个字段的偏移/长度字典,它保证了唯一的名称,并且对移动的字段有弹性,在中间添加新的,等等。 我在尝试引用偏移量时遇到“无法访问静态字段”,如下所示:

    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;
        }
    }
}

构造函数是在静态字段全部初始化之前调用的,请参见谢谢,J.Rush。据我所知,所有类都是这样,而不仅仅是enum-s。元素的第一次实例化会触发静态构造函数并初始化所有静态字段。为什么enum有一个特殊的限制?感谢您提供了如此广泛的注释在我看来,这不是一个有效的解决方案,因为每次都会重新计算偏移量(好像以前什么都没有发生过!)。更合理的方法(我的帖子建议)是在不同的类(比如OffsetClass)中将nextOfs作为静态字段,因此您可以保留原始代码,仅将nextOfs替换为OffsetClass。nextOfs。在重新计算的一开始,我就失去了您……偏移量/大小成员是最终的,并初始化了一次。多次访问FIELD1.offset将不会重新计算任何内容……或者您正在谈论其他内容?
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;
        }
    }
}