web-dev-qa-db-fra.com

Pourquoi compareTo sur une finale Enum en Java?

Une énumération dans Java implémente l'interface Comparable. Il aurait été agréable de remplacer la méthode Comparable de compareTo, mais ici elle est marquée comme finale L'ordre naturel par défaut sur EnumcompareTo est l'ordre répertorié.

Est-ce que quelqu'un sait pourquoi les énumérations Java ont cette restriction?

85
neu242

Par souci de cohérence, je suppose ... quand vous voyez un type enum, vous savez pour un fait que son ordre naturel est l'ordre dans dont les constantes sont déclarées.

Pour contourner ce problème, vous pouvez facilement créer votre propre Comparator<MyEnum> et l'utiliser chaque fois que vous avez besoin d'une commande différente:

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
    }
}

Vous pouvez utiliser le Comparator directement:

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

ou l'utiliser dans des collections ou des tableaux:

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

Plus d'informations:

116
Zach Scrivena

Fournir une implémentation par défaut de compareTo qui utilise l'ordre du code source est très bien; le rendre final était un faux pas de la part de Sun. L'ordinal représente déjà l'ordre de déclaration. Je conviens que dans la plupart des situations, un développeur peut simplement ordonner logiquement ses éléments, mais parfois on veut que le code source soit organisé de manière à ce que la lisibilité et la maintenance soient primordiales. Par exemple:


  //===== 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");

L'ordre ci-dessus semble bon dans le code source, mais ce n'est pas ainsi que l'auteur pense que compareTo devrait fonctionner. Le comportement compareTo souhaité consiste à ordonner par nombre d'octets. L'ordre du code source qui rendrait cela possible dégrade l'organisation du code.

En tant que client d'une énumération, je me fiche de savoir comment l'auteur a organisé son code source. Je veux que leur algorithme de comparaison ait un certain sens, cependant. Sun a inutilement placé les rédacteurs de code source dans une liaison.

35
Thomas Paine

Les valeurs d'énumération sont précisément ordonnées logiquement selon l'ordre dans lequel elles sont déclarées. Cela fait partie de la spécification de langage Java. Par conséquent, il s'ensuit que les valeurs d'énumération ne peuvent être comparées que si elles sont membres de la même énumération. La spécification veut garantir davantage que l'ordre comparable renvoyé par compareTo () est le même que l'ordre dans lequel les valeurs ont été déclarées, c'est la définition même d'une énumération.

6
Martin OConnor

Une explication possible est que compareTo doit être cohérent avec equals.

Et equals pour les énumérations doit être cohérent avec l'égalité d'identité (==).

Si compareTo n'était pas final, il serait possible de le remplacer par un comportement qui n'était pas cohérent avec equals, ce qui serait très contre-intuitif.

2
Lii