#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. Мне определенно нужно будет немного прочитать о том, что именно это делает.