2009-04-07 2 views
11

В Java Enum может делать то, что делают Enums, но также может иметь методы (поведение и логика). Какое преимущество имеет преимущество при использовании класса с использованием перечисления? Простые примеры, чтобы проиллюстрировать этот пункт, также приветствуются.Переменные Java могут иметь поведение?

ответ

14

Вот простой пример:

enum RoundingMode { 
    UP { 
     public double round(double d) { 
      return Math.ceil(d); 
     } 
    }, 
    DOWN { 
     public double round(double d) { 
      return Math.floor(d); 
     } 
    }; 

    public abstract double round(double d); 
} 
+0

Как бы вы использовали это в коде? Я просто это делаю? double foo = RoundingMode.round (20.3); Или вы могли бы перечислить перечисление на дочернее перечисление? Я отбрасываю абстрактным методом. – Dave

+0

Абстрактный метод переопределяется вложенными классами, используемыми UP и DOWN. Вы бы использовали его в коде следующим образом: double doMath (RoundMode m, double x, double y) {double d; ... d = m.round (d); ... return d; } Вы должны передать в RoundingMode.UP или RoundingMode.DOWN в качестве первого параметра. –

+0

Спасибо! Не знаю, как я к этому отношусь, но я это понимаю сейчас;) – Dave

6

Я не совсем уверен, где заголовок вопроса подходит ко всему остальному. Да, перечисления Java имеют поведение. У них тоже может быть состояние, хотя это действительно так, действительно быть неизменным. (Идея изменчивого значения enum довольно страшная IMO.)

Перечисление в Java - это фиксированный набор объектов, в основном. Преимущество в том, что вы знаете, что если у вас есть ссылка на этот тип, то всегда либо null, либо один из известных наборов.

Лично я действительно люблю перечисления Java и хочу, чтобы у C# их тоже было - они намного объективны, чем перечисления C#, которые в основном являются «именованными номерами». Есть несколько «gotchas» с точки зрения порядка инициализации, но они, как правило, потрясающие.

+0

Не может эмулировать Java перечислений с C# классов? –

+0

@Vilx: Конечно, вы можете. Перед Java 5 вы можете написать свои собственные классы, чтобы создавать типы объектов enum enum. (Ну, вы все равно можете, конечно, просто нечего.) – Eddie

+0

Vilx: Вы можете, но это немного противно. В основном вы используете абстрактный базовый тип с частным конструктором и извлекаете из него * вложенные * типы, которые могут вызывать частный конструктор. –

1

В нашем проекте мы используем Enums для нескольких вещей, но, возможно, наиболее заметно для целей i18n - каждому изображенному тексту предоставляется Enum. Класс Enum имеет метод String-return, который проверяет используемый Locale и выбирает правильный перевод из коллекции переводов во время выполнения.

Это двойное назначение - вы получаете завершение кода из своей IDE, а также никогда не забываете переводить строку.

Использование очень просто, к тому, что это почти rendundant привести пример, но вот как можно было бы использовать перевод-перечисление

System.out.println(Translations.GREET_PERSON.trans()+" "+user.getName()); 

Или, если вы хотите быть фантазии, есть Enum принимать аргументы, которые будут с некоторой магической работы со строками, вставляться в отмеченной позиции в строке переводов

System.out.println(Translations.GREET_PERSON.trans(user.getName()); 
+0

Интересное использование, но похоже, что вы можете получить такое же поведение из серии статических методов в классе. Думаю, я не вижу преимущества использования перечисления. – Dave

+0

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

8

Enum типы также являются отличным способом реализации истинных синглетонов.

Классические одноэлементные шаблоны в Java обычно включают частные конструкторы и общедоступные статические методы, но все еще уязвимы для создания экземпляров посредством отражения или (дезадаптации). Тип перечисления защищает от этого.

+0

Хотя вы получаете некоторый нечетный метод «бесплатно». (В любом случае, синглтоны - зло.) –

+0

Я не понимаю комментария. –

+0

Интересные точки. Как перевязка защищает от отражения и десериализации? Наверное, я спрашиваю, что на самом деле мешает мне создавать экземпляр enum через отражение? Вызывает ли компилятор исключенное исключение? – Dave

2

Поскольку экземпляры перечисления являются одиночными, вы можете использовать их в операциях switch или с == для проверки равенства.

2

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

Вы можете эмулировать «известный фиксированный набор возможных экземпляров» с обычными классами (шаблон «typafe enum», описанный в бесчисленных книгах и статьях), но это довольно некоторая работа (повторяющаяся для каждого такого класса), чтобы получить ее работают действительно правильно в отношении сериализации, equals() и hashCode() и, возможно, некоторые другие вещи, которые я забыл. Перечисления на уровне языка избавляют вас от этой работы. И, как упоминалось выше, в операторах switch могут использоваться только перечисления уровня языка.

+0

Это классы, но есть разница на уровне байт-кода. Во-первых, классы перечисления имеют флаг ACC_ENUM. См. Http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf. –

0

Взгляните на классы времени java/joda, где перечисления выполняют чертовски много работы.

Вот пример java.time.Month:

public enum Month implements TemporalAccessor, TemporalAdjuster { 
    JANUARY, 
    FEBRUARY, 
    MARCH, 
    APRIL, 
    MAY, 
    JUNE, 
    JULY, 
    AUGUST, 
    SEPTEMBER, 
    OCTOBER, 
    NOVEMBER, 
    DECEMBER; 

    private static final Month[] ENUMS = Month.values(); 

    public static Month of(int month) { 
     if (month < 1 || month > 12) { 
      throw new DateTimeException("Invalid value for MonthOfYear: " + month); 
     } 
     return ENUMS[month - 1]; 
    } 

    // About a dozen of other useful methods go here 

} 
Смежные вопросы