100

Java 中的枚举实现了该Comparable接口。重写ComparablecompareTo方法会很好,但在这里它被标记为最终的。Enum's上的默认自然顺序compareTo是列出的顺序。

有谁知道为什么 Java 枚举有这个限制?

4

5 回答 5

124

为了一致性,我猜......当你看到一个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);    

更多的信息:

于 2009-02-06T10:46:00.490 回答
41

提供使用源代码排序的 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 不必要地束缚了源代码编写者。

于 2010-07-09T17:23:05.700 回答
6

枚举值根据它们声明的顺序在逻辑上精确排序。这是 Java 语言规范的一部分。因此,枚举值只能在它们是同一个 Enum 的成员时进行比较。规范希望进一步保证 compareTo() 返回的可比较顺序与声明值的顺序相同。这就是枚举的定义。

于 2009-02-06T10:46:42.003 回答
2

一种可能的解释是compareTo应该与equals.

并且equals对于枚举应该与身份相等(==)一致。

如果compareTowhere 是非最终的,则可以用与 不一致的行为来覆盖它equals,这将是非常违反直觉的。

于 2015-09-09T14:08:00.890 回答
-1

如果要更改枚举元素的自然顺序,请在源代码中更改它们的顺序。

于 2009-02-06T10:27:01.293 回答