Создание карты перечисления из конструктора Enum для статической карты

#java #enums #hashmap

#java #перечисления #hashmap

Вопрос:

Хорошо, теперь у меня есть EnumMap, но он все равно не работает. Например, когда я пытаюсь сделать это:

             Status inStatus = Enum.valueOf(Status, ENUM_MAP.get(02));
 

Его inStatus заканчивается нулевым значением :

да.

Я работаю на Java, и, по сути, на данный момент у меня есть это:

 private static final HashMap<Integer,Status> ENUM_MAP = 
                    new HashMap<Integer,Status>();
...
ENUM_MAP.put(0, Status.A);
ENUM_MAP.put(1, Status.B);
ENUM_MAP.put(2, Status.C);
 

И это работает. Но я хочу, чтобы мой enum делал это внутренне примерно так, но это не работает.

 public static enum Status{
    A(0),B(1),C(2);
    protected static final HashMap<Integer,Status> ENUM_MAP =
                    new HashMap<Integer,Status>();
    private final Integer state;
    private Status(Integer state){
        this.state = state;
        ENUM_MAP.put(this.state, **this**);
    }
}
 

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

Редактировать:

Это, казалось, работало лучше всего, только 2 дополнительные строки (хотя мой компилятор говорит мне, что он протекает) И он сохраняет мою карту такой приватной, какой я хотел.

     private static final Map<Integer,Status> ENUM_MAP=new HashMap<>();

    public static enum Status{
        A(0),B(1),C(2);
        private final Integer state;
        private Status(Integer state){
            this.state=state;
            ENUM_MAP.put(this.state, this);
        }//end private Status(int state)
 

Комментарии:

1. Вы пытаетесь получить встроенное преобразование из целочисленного порядкового номера в соответствующее ему значение enum?

2. Что не «приятно и легко» в необходимости писать this ?

3. Существуют неприятные правила определения области видимости. tl;dr вы можете это сделать, но вам нужно поместить инициализацию карты в static блок (и использовать EnumMap , и обернуть его, unmodifiableMap прежде чем присваивать его константе).

4. @ernest_k В этом случае переход от порядкового номера был бы в порядке, но я также пытался перейти от присвоенных значений (т. Е. Предположим, что 0,1,2 было 4, 18,47, вместо этого) Я вроде бы хотел знать, как выполнить оба варианта, для справки. @Sweeper, на самом деле это не позволяет вам помещать this туда. Я хочу, где это должно быть состояние. A, статус. B и статус. C соответственно. @chrylis-осторожно оптимистично — я рассмотрел некоторые вопросы, которые это сделали, но в качестве ключа у них было enum, но я хочу, чтобы Integer был ключом, EnumMap это не нравится, насколько я понимаю.

5. @Sweeper На самом деле это позволило мне использовать это, но не так, как это было раньше по причинам.

Ответ №1:

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

Вот что вы могли бы сделать (вы все равно должны сделать доступным метод поиска)::

 public static enum Status {
    A(0), B(1), C(2);

    protected static final HashMap<Integer, Status> ENUM_MAP = 
            new HashMap<Integer, Status>();
    private final Integer state;

    private Status(Integer state) {
        this.state = state;
    }

    //finds a mapped value or maps one for the key
    public static Status find(int i) {
        if (ENUM_MAP.containsKey(i)) {
            return ENUM_MAP.get(i);
        }

        Status found = null;
        for (Status s : values()) {
            if (i == s.state) {
                found = s;
                ENUM_MAP.put(i, s);
                break;
            }
        }

        return found;
    }
}
 

Комментарии:

1. Я пытался избежать того, чтобы что-либо было общедоступным в классе, хотя это интересный вариант. Некоторые другие ответы привели меня к тому, что мне было нужно.

2. @procersapientiae итак, где вам нужно разрешить отображение? изнутри самого класса enum?

3. да, я надеялся, что единственное, что будет отображаться, — это защищенное перечисление, но я доволен тем, что я выбрал, другой вариант использования статического блока сработал бы для сохранения его внутренним, но принадлежность к классу owner работала лучше.

Ответ №2:

Вы можете использовать внутренний класс для хранения статической карты:

 public static class Holder {
    static Map<Integer, Status> statusMap = new HashMap<>();
}
private Status(Integer state){
    this.state = state;
    Holder.statusMap.put(state, this);
}
public static Status byState(Integer state) {
    return Holder.statusMap.get(state;
}
 

Я не хочу, чтобы состояние было общедоступным — если состояние является ключом к вашей карте, вы, вероятно, отправите состояние, поэтому я не понимаю вашего комментария

Комментарии:

1. Затем, когда я пытаюсь использовать его вне класса, он говорит, что не может найти держателя пакета. :

2. @procersapientiae добавлен byState метод

3. Я пытался сохранить все это в тайне, ваш ответ помог мне синтезировать решение, если вы проверите мой вопрос, я отредактировал его на основе ваших отзывов.

Ответ №3:

Вы можете использовать статический блок:

 public enum Status{
    A(0),B(1),C(2);
    protected static final HashMap<Integer,Status> ENUM_MAP =
                    new HashMap<Integer,Status>();

    static {
      for(Status status : Status.values()) {
        ENUM_MAP.put(status.state, status);
      }
    }
    private final Integer state;
    private Status(Integer state){
        this.state = state;
    }
}
 

Комментарии:

1. О, это начинает иметь смысл для меня. Это потому, что код в начале класса выполняется, поэтому он создает экземпляры самого себя с помощью частного конструктора, а затем выполняет то, что находится в случайном статическом блоке дальше? Вероятно, это сделало бы так, что мне никогда не нужно было создавать состояния, если бы я хотел использовать ordinal() .

2. Другой вопрос, если это делается в конструкторе против статического блока, происходит ли это во время компиляции или выполнения?

3. Они происходят во время выполнения. static ключевое слово означает, что эта часть кода принадлежит самому классу, а не его экземплярам. Enum на самом деле является специфическим типом класса. Все его поля могут быть записаны как public static final A = new Status(1); ...

4. Спасибо за разъяснение, я начал понимать это после того, как запутался, почему я мог использовать and enum как общее расширенное перечисление (прописное), и теперь все это имеет смысл.

Ответ №4:

Это (хотя и длинное) однострочное определение ENUM_MAP является окончательным и неизменяемым и будет содержать все значения состояния, если вы добавите больше. Безопасно использовать в качестве общедоступного члена — последующие изменения не допускаются, поскольку в объявлении используется Map.copyOf() :

 public enum Status{
    A(0),B(1),C(2);
    private final Integer state;
    private Status(Integer state){
        this.state=state;
    }
    public static final Map<Integer,Status> ENUM_MAP = 
        Map.copyOf(Arrays.stream(values())
                         .collect(Collectors.toMap(st -> st.state, st -> st)));
 

Значение ENUM_MAP инициализируется всеми значениями enum по состоянию ключа к значению перечисления.

В этом примере программы показано, как искать значения перечислений по состоянию или имени, включая Status.valueOf(String) :

 public static void main(String[] args)
{
    System.out.println("ENUM_MAP=" Status.ENUM_MAP);
    System.out.println("ENUM_MAP.get(1)=" Status.ENUM_MAP.get(1));
    System.out.println("ENUM_MAP.get(5)=" Status.ENUM_MAP.get(5));

    System.out.println("Status.valueOf("A")=" Status.valueOf("A"));
    System.out.println("Enum.valueOf(Status.class, "A")=" Enum.valueOf(Status.class, "A"));

    // Next line fails (as expected) as ENUM_MAP cannot be changed
    Status.ENUM_MAP.put(10, Status.C);
}
 

Это печатает:

 ENUM_MAP={0=A, 1=B, 2=C}
ENUM_MAP.get(1)=B
ENUM_MAP.get(5)=null
Status.valueOf("A")=A
Enum.valueOf(Status.class, "A")=A
Exception in thread "main" java.lang.UnsupportedOperationException
 

Вызов Status.valueOf("A") выполняет то же Enum.valueOf(Status.class, "A") самое, что и .

Комментарии:

1. Мне определенно нужно будет немного прочитать о том, что именно это делает.