Java:无法在枚举中使用 EnumSet:初始化错误:技术研究人才树示例

2022-01-18 00:00:00 initialization enums casting java

错误:

...
Caused by: java.lang.ExceptionInInitializerError
...
Caused by: java.lang.ClassCastException: 
class com.evopulse.ds2150.TechTrees$BuildingTechTree
not an enum
at java.util.EnumSet.noneOf(Unknown Source)
at java.util.EnumSet.of(Unknown Source)
at com.evopulse.ds2150.TechTrees$BuildingTechTree.<clinit>(TechTrees.java:38)

这是我列举的片段

public enum BuildingTechTree {
//Name                      SoftName                    Requirements    
NONE                        ("NULL",                    null),

--> 下一行是崩溃的地方

--> This next line is where it crashes

BARRACKS                    ("Barracks",                EnumSet.of(NONE),
WALLS_SANDBAGS              ("Sandbag wall",            EnumSet.of(NONE),

POWERPLANT                  ("Power plant",             EnumSet.of(BARRACKS)),
GUARDTOWER                  ("Guard Tower",             EnumSet.of(BARRACKS));

将 EnumSet.of(NONE) 和 EnumSet.of(BARRACKS) 替换为 null,让初始化工作,但由于缺少数据结构而破坏了我的代码......显然,但我这样做是为了测试我的代码的其余部分不是某种原因.

Replacing EnumSet.of(NONE) and EnumSet.of(BARRACKS) with null, lets initialization work, but breaks my code, due to missing data structure... obviously, but I did it to test the rest of my code wasn't somehow the cause.

删除 EnumSet.of(NONE) 并仅替换为 NONE,BARRACKS 也是如此,并更改所有相关的变量、构造函数和方法,这也不起作用......(甚至无法使用contains.all,因为 is 不是适用于我更改的变量"...)

Removing EnumSet.of(NONE) and replacing with just NONE, and the same for BARRACKS, and changing all related variables, constructor, and methods, that didn't work either... (and even couldn't use the contains.all, since is wasn't "applicable to my changed variable"... )

我扩展了这个例子,使用了第二个实现:https://gamedev.stackexchange.com/a/25652/48573

I extended this example, using the second implementation: https://gamedev.stackexchange.com/a/25652/48573

我还尝试通过逐字复制示例来追溯我的步骤.添加了

I also tried retracing my steps by copying the example verbatim. added

private static Set<BuildingTechTree> techsKnown;

techsKnown = (BuildingTechTree.BIODOME);
test = TechTrees.researchTech(techsKnown);

调用另一个类来测试初始化​​.不得不改变

to another class to be called from for testing initialization. and had to change

public boolean researchTech(BuildingTechTree tech) {

静态

这导致了同样的in not an enum"错误.我没有任何代表,可以评论他的回答以指出初始化错误...

This resulted in the same "in not an enum" error. I don't have any rep, to comment on his answer to point out the initialization error...

添加了两个当前答案的信息,因为两种解决方案都会导致相同的新错误:

public class TechTrees {
private static Set<BuildingTechTree> techsKnown;

public TechTrees() {
    techsKnown = EnumSet.of(BuildingTechTree.NONE);       //Using this
    techsKnown = EnumSet.noneOf(BuildingTechTree.class);  //Or this
}

public static boolean researchTech(BuildingTechTree tech) {
    if (techsKnown.containsAll(tech.requirements)) {      //Causes null pointer
        return true;                                      //exception @ techsKnown  
    }
    return false;
}

推荐答案

你的声明结构太聪明了,可惜它不起作用.但是 EnumSet 显然需要先完全初始化枚举.它尝试从枚举中获取常量数组,以便知道其内部位集需要多少空间.

Your declaration structure is so clever it's a shame it doesn't work. But EnumSet apparently needs the enum to be fully initialized first. It tries to fetch the array of constants from the enum so that, among other things, it knows how much space is needed for its internal bitset.

这是一种解决方法.它使用一个辅助方法,首先创建一个普通集合 (HashSet),然后,在静态初始化块中,它迭代枚举常量并将所有集合替换为 EnumSet秒.

Here's one workaround. It uses a helper method that creates an ordinary set (HashSet) first, and then, in a static initialization block, it iterates the enum constants and replaces all the sets with EnumSets.

public enum BuildingTechTree {
    // Named constants
    //Name                      SoftName                        Requirements
    NONE                        ("NULL",                        null),
    BARRACKS                    ("Barracks",                    setOf(NONE)),
    WALLS_SANDBAGS              ("Sandbag wall",                setOf(NONE)),
    POWERPLANT                  ("Power plant",                 setOf(BARRACKS)),
    GUARDTOWER                  ("Guard Tower",                 setOf(BARRACKS));

    private final String softName;
    private Set<BuildingTechTree> requirements;

    private BuildingTechTree(String softName, Set<BuildingTechTree> requirements) {
        this.softName = softName;
        this.requirements = requirements;
    }

    private static Set<BuildingTechTree> setOf(BuildingTechTree... values) {
        return new HashSet<>(Arrays.asList(values));
    }

    static {
        for (BuildingTechTree v : values()) {
            if (v.requirements == null) {
                v.requirements = EnumSet.noneOf(BuildingTechTree.class);
            } else {
                v.requirements = EnumSet.copyOf(v.requirements);
            }
        }
    }
}

相关文章