Почему сравнение на Enum final в Java? - PullRequest
82 голосов
/ 06 февраля 2009

Перечисление в Java реализует интерфейс Comparable. Было бы неплохо переопределить метод Comparable compareTo, но здесь он помечен как окончательный. Естественный порядок по умолчанию для Enum s compareTo является перечисленным порядком.

Кто-нибудь знает, почему перечисления Java имеют такое ограничение?

Ответы [ 5 ]

115 голосов
/ 06 февраля 2009

Для согласованности, я думаю ... когда вы видите тип enum, вы знаете для факта , что его естественный порядок - это порядок, в котором объявлены константы.

Чтобы обойти это, вы можете легко создать свой собственный Comparator<MyEnum> и использовать его всякий раз, когда вам нужен другой порядок:

enum MyEnum
{
    DOG("woof"),
    CAT("meow");

    String sound;    
    MyEnum(String s) { sound = s; }
}

class MyEnumComparator implements Comparator<MyEnum>
{
    public int compare(MyEnum o1, MyEnum o2)
    {
        return -o1.compareTo(o2); // this flips the order
        return o1.sound.length() - o2.sound.length(); // this compares length
    }
}

Вы можете использовать Comparator напрямую:

MyEnumComparator c = new MyEnumComparator();
int order = c.compare(MyEnum.CAT, MyEnum.DOG);

или используйте его в коллекциях или массивах:

NavigableSet<MyEnum> set = new TreeSet<MyEnum>(c);
MyEnum[] array = MyEnum.values();
Arrays.sort(array, c);    

Дополнительная информация:

35 голосов
/ 09 июля 2010

Обеспечение реализации по умолчанию для CompareTo, которая использует упорядочение исходного кода, прекрасно; сделать это было ошибкой со стороны Sun. Порядковый номер уже учитывает порядок декларирования. Я согласен с тем, что в большинстве ситуаций разработчик может просто логически упорядочить свои элементы, но иногда хочется, чтобы исходный код был организован таким образом, чтобы удобство чтения и обслуживания было первостепенным. Например:


  //===== SI BYTES (10^n) =====//

  /** 1,000 bytes. */ KILOBYTE (false, true,  3, "kB"),
  /** 10<sup>6</sup> bytes. */   MEGABYTE (false, true,  6, "MB"),
  /** 10<sup>9</sup> bytes. */   GIGABYTE (false, true,  9, "GB"),
  /** 10<sup>12</sup> bytes. */  TERABYTE (false, true, 12, "TB"),
  /** 10<sup>15</sup> bytes. */  PETABYTE (false, true, 15, "PB"),
  /** 10<sup>18</sup> bytes. */  EXABYTE  (false, true, 18, "EB"),
  /** 10<sup>21</sup> bytes. */  ZETTABYTE(false, true, 21, "ZB"),
  /** 10<sup>24</sup> bytes. */  YOTTABYTE(false, true, 24, "YB"),

  //===== IEC BYTES (2^n) =====//

  /** 1,024 bytes. */ KIBIBYTE(false, false, 10, "KiB"),
  /** 2<sup>20</sup> bytes. */   MEBIBYTE(false, false, 20, "MiB"),
  /** 2<sup>30</sup> bytes. */   GIBIBYTE(false, false, 30, "GiB"),
  /** 2<sup>40</sup> bytes. */   TEBIBYTE(false, false, 40, "TiB"),
  /** 2<sup>50</sup> bytes. */   PEBIBYTE(false, false, 50, "PiB"),
  /** 2<sup>60</sup> bytes. */   EXBIBYTE(false, false, 60, "EiB"),
  /** 2<sup>70</sup> bytes. */   ZEBIBYTE(false, false, 70, "ZiB"),
  /** 2<sup>80</sup> bytes. */   YOBIBYTE(false, false, 80, "YiB");

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

Как клиент перечисления, мне было все равно, как автор организовал их исходный код. Однако я хочу, чтобы их алгоритм сравнения имел какой-то смысл. Sun без необходимости ставит авторов исходного кода в тупик.

6 голосов
/ 06 февраля 2009

Значения перечисления точно упорядочены логически в соответствии с порядком их объявления. Это часть спецификации языка Java. Отсюда следует, что значения перечисления можно сравнивать, только если они являются членами одного и того же Enum. Спецификация хочет дополнительно гарантировать, что сопоставимый порядок, возвращаемый методом CompareTo (), совпадает с порядком, в котором были объявлены значения. Это само определение перечисления.

2 голосов
/ 09 сентября 2015

Одним из возможных объяснений является то, что compareTo должно соответствовать equals.

И equals для перечислений должны соответствовать идентичности равенства (==).

Если compareTo, где он не является окончательным, его можно переопределить поведением, которое не соответствует equals, что было бы очень нелогичным.

0 голосов
/ 06 февраля 2009

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

...