Java: невозможно использовать EnumSet в Enumeration: ошибка инициализации: пример дерева технических исследований

Ошибка:

...
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),

- > В этой следующей строке происходит сбой

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, позволяет инициализировать работу, но прерывает мой код из-за отсутствия структуры данных... очевидно, но я сделал это, чтобы проверить остальную часть моего кода не было чем-то причиной.

Удаление EnumSet.of(NONE) и замена с помощью NONE, а также для BARRACKS, а также изменение всех связанных переменных, конструктора и методов, которые тоже не работали... (и даже не могли использовать contains.all, так как не был "применим к моей измененной переменной"...)

Я продлил этот пример, используя вторую реализацию: https://gamedev.stackexchange.com/a/25652/48573

Я также попытался восстановить мои шаги, скопировав пример дословно. добавлено

private static Set<BuildingTechTree> techsKnown;

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

для другого класса, который должен быть вызван для проверки инициализации. и пришлось изменить

public boolean researchTech(BuildingTechTree tech) {

до статического

Это привело к ошибке "in not an enum". У меня нет комментариев, чтобы прокомментировать его ответ, чтобы указать на ошибку инициализации...

Добавлена ​​информация для обоих текущих ответов, так как оба решения вызывают одну и ту же новую ошибку:

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

Ответ 1

Ваша структура декларации настолько умна, что стыдно, что она не работает. Но EnumSet, очевидно, необходимо, чтобы перечисление было полностью инициализировано первым. Он пытается получить массив констант из перечисления, чтобы, среди прочего, он знал, сколько места необходимо для его внутреннего битового набора.

Вот один способ обхода. Он использует вспомогательный метод, который сначала создает обычный набор (HashSet), а затем в статическом блоке инициализации он выполняет итерацию констант перечисления и заменяет все наборы с помощью EnumSet s.

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

Ответ 2

У вас проблема с курицей и яйцом. Вы можете реорганизовать свое перечисление на что-то вроде этого:

public enum BuildingTechTree {

    NONE("NULL"),
    BARRACKS("Barracks"),
    WALLS_SANDBAGS("Sandbag wall"),
    POWERPLANT("Power plant"),
    GUARDTOWER("Guard Tower");

    static {
        NONE.trees = EnumSet.noneOf(BuildingTechTree.class);
        BARRACKS.trees = EnumSet.of(NONE);
        WALLS_SANDBAGS.trees = EnumSet.of(NONE);
        POWERPLANT.trees = EnumSet.of(BARRACKS);
        GUARDTOWER.trees = EnumSet.of(BARRACKS);
    }

    private String name;
    private Set<BuildingTechTree> trees;

    private BuildingTechTree(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public Set<BuildingTechTree> getTrees() {
        return Collections.unmodifiableSet(trees);
    }
}

EDIT:

относительно вашей второй проблемы: вы получаете доступ к статической переменной из статического метода. Но эта переменная инициализируется при вызове конструктора класса (что является большой проблемой проектирования). Не используйте нестатические статические поля. И не инициализируйте статические поля из методов экземпляра или конструкторов. Это не имеет смысла. Вы не устанавливаете цвет, который должны иметь все автомобили при строительстве автомобиля. Статично статируйте статические поля:

public class TechTrees {
    private static final Set<BuildingTechTree> TECHS_KNOWN =
        EnumSet.of(BuildingTechTree.NONE);

    public static boolean researchTech(BuildingTechTree tech) {
        return TECHS_KNOWN.containsAll(tech.requirements));
    }
}