Почему compareTo на Enum final в Java?
перечисление в Java реализует Comparable
интерфейс. Было бы неплохо переопределить Comparable
' s compareTo
метод, но здесь он помечен как окончательный. Естественный порядок по умолчанию на Enum
' s compareTo
это перечисленном порядке.
кто-нибудь знает, почему перечисления Java имеют это ограничение?
5 ответов:
для согласованности я думаю... когда вы видите
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);
далее информация:
предоставление реализации по умолчанию compareTo, которая использует порядок исходного кода, отлично; сделать его окончательным было ошибкой со стороны Sun. Порядковый номер уже учитывает порядок объявления. Я согласен, что в большинстве ситуаций разработчик может просто логически упорядочить свои элементы, но иногда требуется, чтобы исходный код был организован таким образом, чтобы читаемость и обслуживание были первостепенными. Например:
//===== SI BYTES (10^n) =====// /** 1,000 bytes. */ KILOBYTE (false, true, 3, "kB"), /** 106 bytes. */ MEGABYTE (false, true, 6, "MB"), /** 109 bytes. */ GIGABYTE (false, true, 9, "GB"), /** 1012 bytes. */ TERABYTE (false, true, 12, "TB"), /** 1015 bytes. */ PETABYTE (false, true, 15, "PB"), /** 1018 bytes. */ EXABYTE (false, true, 18, "EB"), /** 1021 bytes. */ ZETTABYTE(false, true, 21, "ZB"), /** 1024 bytes. */ YOTTABYTE(false, true, 24, "YB"), //===== IEC BYTES (2^n) =====// /** 1,024 bytes. */ KIBIBYTE(false, false, 10, "KiB"), /** 220 bytes. */ MEBIBYTE(false, false, 20, "MiB"), /** 230 bytes. */ GIBIBYTE(false, false, 30, "GiB"), /** 240 bytes. */ TEBIBYTE(false, false, 40, "TiB"), /** 250 bytes. */ PEBIBYTE(false, false, 50, "PiB"), /** 260 bytes. */ EXBIBYTE(false, false, 60, "EiB"), /** 270 bytes. */ ZEBIBYTE(false, false, 70, "ZiB"), /** 280 bytes. */ YOBIBYTE(false, false, 80, "YiB");
приведенный выше порядок выглядит хорошо в исходном коде, но не является как автор считает, что compareTo должен работать. Желаемое поведение compareTo должно иметь порядок по количеству байтов. Упорядочение исходного кода, которое могло бы это сделать, ухудшает организацию кода.
как клиент перечисления мне было все равно, как автор организовал их исходный код. Однако я хочу, чтобы их алгоритм сравнения имел какой-то смысл. Солнце необоснованно положил писателей исходный код в безвыходном положении.
значения перечисления точно упорядочены логически в соответствии с порядком, в котором они объявлены. Это часть спецификации языка Java. Следовательно, значения перечисления могут сравниваться только в том случае, если они являются членами одного и того же перечисления. Спецификация хочет дополнительно гарантировать, что сопоставимый порядок, возвращаемый compareTo (), совпадает с порядком, в котором были объявлены значения. Это само определение перечисления.
одно из возможных объяснений заключается в том, что
compareTo
должно соответствоватьequals
.и
equals
для перечислений должно быть совместимо с равенством идентичности (==
).если
compareTo
где быть не окончательным можно было бы переопределить его с поведением, которое не согласуется сequals
, что было бы очень нелогично.