Почему CompareTo в финале Enum в Java?
-
21-08-2019 - |
Вопрос
Перечисление в Java реализует Comparable
интерфейс.Было бы неплохо переопределить Comparable
's compareTo
метод, но здесь он помечен как окончательный.Естественный порядок по умолчанию на Enum
's compareTo
указанный порядок.
Кто-нибудь знает, почему перечисления Java имеют это ограничение?
Решение
Для последовательности, я думаю...когда ты видишь 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 заключается в том, чтобы упорядочить число байтов.Такое упорядочение исходного кода ухудшает организацию кода.
Как клиент перечисления, мне было все равно, как автор организовал свой исходный код.Однако я хочу, чтобы их алгоритм сравнения имел какой-то смысл.Sun без необходимости поставила авторов исходного кода в затруднительное положение.
Значения перечисления точно упорядочены логически в соответствии с порядком их объявления.Это часть спецификации языка Java.Следовательно, значения перечисления можно сравнивать только в том случае, если они являются членами одного и того же Enum.Спецификация хочет дополнительно гарантировать, что порядок сравнения, возвращаемый функцией CompareTo(), совпадает с порядком, в котором были объявлены значения.Это само определение перечисления.
Одно из возможных объяснений состоит в том, что compareTo
должно соответствовать equals
.
И equals
для перечислений должно соответствовать равенству идентичности (==
).
Если compareTo
где, чтобы быть не окончательным, можно было бы переопределить его поведением, которое не соответствовало бы equals
, что было бы очень нелогично.
Если вы хотите изменить естественный порядок элементов вашего перечисления, измените их порядок в исходном коде.