Задать перечисление с помощью int, специфичного для этого перечисления? - PullRequest
17 голосов
/ 03 июня 2011

Привет всем. Итак, у меня есть набор перечислений и БД с целыми числами, соответствующими этим перечислениям. Примерно так, например:

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }
}

У меня также есть база данных, которая ссылается на эти дни только целыми числами, которые соответствуют их int в перечислении выше. То, что я хочу сделать, это запросить базу данных, которая вернет целое число, а затем установить перечислитель для объекта на основе этого целого числа, возвращенного из базы данных. Я мог бы сделать что-то вроде этого:

public static Day getDay(int i) {
    switch(i) {
    case 1:
        return Day.SUNDAY;
    case 2: 
        return Day.MONDAY;
    //And so on
    }
}

Но для набора перечислений с более чем 100 перечислениями внутри это не кажется очень практичным.

Так есть ли способ сделать это? Опять же, моя цель - просто вставить значение типа int и получить перечислитель без необходимости создавать новый метод для многих перечислений в этом наборе. Может быть, я должен просто сделать это своим собственным классом, а не перечислителем, но я надеялся сделать это таким образом. Спасибо!

Ответы [ 6 ]

10 голосов
/ 03 июня 2011

Вот простая реализация, которая будет работать:

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }

    public static Day forInt(int id) {
        for (Day day : values()) {
            if (day.fId == id) {
                return day;
            }
        }
        throw new IllegalArgumentException("Invalid Day id: " + id);
    }
}

Если вы знаете, что ваши перечисления начинают считать с 1, вы можете просто использовать это вместо:

public static Day forInt(int id) {
    return values()[id - 1];
}
9 голосов
/ 03 июня 2011

Перечисления имеют встроенный идентификационный номер, «порядковый номер», который вы можете использовать для этой цели, если у вас есть простой способ перейти от числа, представляющего данное значение в базе данных, к порядковому номеру перечисление Порядковые значения присваиваются значениям перечисления в порядке их объявления в исходном файле, начиная с 0, поэтому в вашем примере SUNDAY будет иметь порядковый номер 0, MONDAY = 1 и т. Д.

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

private static Day[] values = Day.values();
public static Day getDay(int i) {
    return values[i - 1];
}

Если порядок значений перечисления в соответствии с их идентификаторами базы данных совпадает с порядком, в котором они объявлены в исходном коде, то вы можете в значительной степени просто использовать вышеуказанный метод как есть (за исключением изменения имени класса) , В противном случае вам, возможно, придется сделать что-то более сложное, чтобы сопоставить значения базы данных с порядковыми номерами; возможно, создание массива, если отображение сильно нелинейное.

P.S. И, конечно, если вы сделаете это, поле fId будет бесполезно.

6 голосов
/ 03 июня 2011

Ваш перечисляющий класс должен иметь карту поиска, встроенную как статическая переменная. Следовательно, ваш enum-класс должен быть примерно таким.

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }


   private static final Map<Integer, Day > lookup
   = new HashMap<Integer, Day >();

   static {
   for (Day s : EnumSet.allOf(Day.class))
         lookup.put(s.getIntValue(), s);
   }

   public static Day getValue(int intValue) {
      return lookup.get(intValue);
   }

}

Затем, чтобы получить правильное перечисление на основе int i, вы можете просто вызвать

Day.getValue(i);

Этот подход будет работать, даже если нумерация нелинейная или в ней есть пробелы.

1 голос
/ 03 июня 2011

Отредактировано - кэш создан ленивым.

Вы можете создать Map<Integer,Day> среду выполнения и использовать ее в реализации getDay.

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    private static Map<Integer,Day> CACHE = null;

    private static void lazyFillCache() {
        if (CACHE != null) return;

        final Map<Integer,Day> c = new HashMap<Integer,Day>();
        for (final Day d : Day.values()) {
            c.put(d.fId, d);
        }

        CACHE = c;
    }

    public static Day getDay(int i) {
        lazyFillCache();
        return CACHE.get(i);
    }

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }
}

Редактировать - Вдохновленный комментарием Тома Хоутинса здесь , вы также можете использовать эту реализацию, которая использует возможности загрузки классов Java:

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    private static class Cache {
        private static Map<Integer,Day> CACHE = new HashMap<Integer,Day>();

        static {
            for (final Day d : Day.values()) {
                CACHE.put(d.fId, d);
            }
        }
    }

    public static Day getDay(int i) {
        return Cache.CACHE.get(i);
    }

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }
}
0 голосов
/ 25 мая 2015

Day myDay = Day.values ​​() [x] - x - это значение типа int

0 голосов
/ 03 июня 2011

Day.values ​​() вернет (основанный на нуле) массив значений перечисления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...