JavaのEnum finalでcompareToを使用するのはなぜですか?


93

Javaの列挙型がComparableインターフェースを実装します。ComparablecompareToメソッドをオーバーライドすると良かったのですが、ここではfinalとマークされています。上のデフォルトの自然な順序EnumさんがcompareToリストされているためです。

Java列挙型にこの制限がある理由を誰かが知っていますか?


効果的なJava-第3版の項目10に非常に細かい説明があります(equals()で対処していますが、項目14で、compareTo()の問題は同じであることがわかります)。つまり、インスタンス化可能なクラス(列挙型など)を拡張して値コンポーネントを追加すると、equals(またはcompareTo)コントラクトを保持できなくなります。
クリスチャンH.クーン

回答:


121

一貫性を保つために、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);    

さらに詳しい情報:


カスタムコンパレータは、コレクションにEnumを提供する場合にのみ効果的です。直接比較したい場合はそれほど役に立ちません。
マーティンOConnor

7
はい、そうです。新しいMyEnumComparator.compare(enum1、enum2)。Etvoilá。
ボンベ、

@martinoconnor&Bombe:私はあなたのコメントを回答に組み込んだ。ありがとう!
Zach Scrivena 2009

MyEnumComparator状態がないので、特に@Bombeが示唆することをしている場合は、シングルトンである必要があります。代わりに、MyEnumComparator.INSTANCE.compare(enum1, enum2)不要なオブジェクトの作成を回避するようなことをします
kbolino '27

2
@kbolino:コンパレーターイベントは、列挙型クラス内のネストされたクラスである可能性があります。LENGTH_COMPARATOR列挙型の静的フィールドに格納できます。そのようにして、列挙型を使用している誰にとっても簡単に見つけることができます。
Lii

39

ソースコードの順序付けを使用する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は、ソースコードの作成者を不必要にバインドしました。


3
同意します。私の列挙型では、誰かが注意を払わないと壊れる可能性がある注文の代わりに、ビジネスに匹敵するアルゴリズムを使用できるようにしたいと思います。
TheBakker

6

列挙値は、宣言された順序に従って論理的に正確に並べられます。これはJava言語仕様の一部です。したがって、列挙値は同じEnumのメンバーである場合にのみ比較できるということになります。この仕様では、compareTo()によって返される比較可能な順序が、値が宣言された順序と同じであることをさらに保証したいと考えています。これがまさに列挙の定義です。


トーマスペインが彼の例で明らかにしたように、言語は構文ではなく、セマンティクスでは順序付けできません。あなたは言う、項目は論理的に順序付けられていますが、列挙型を理解する方法では、項目は論理的な方法でカプセル化されています。
Bondax

2

考えられる説明の1つは、compareToと一致する必要があるというものequalsです。

またequals、列挙型はIDの等価性と一致している必要があります(==)。

compareTo最終でない場所を指定する場合、と一致しない動作でオーバーライドすることが可能でありequals、直感に反することになります。


compareTo()はequals()と一貫性があることが推奨されていますが、必須ではありません。
クリスチャンH.クーン

-1

列挙型の要素の自然な順序を変更したい場合は、ソースコードでそれらの順序を変更します。


うん

はい。ただし、compareTo()をオーバーライドする理由を実際には説明しません。だから私の結論は、あなたが何かを悪いことをしようとしているということでした。
ボンベ、

コンピュータが私よりもはるかに優れているのに、なぜ手動でエントリを並べ替える必要があるのか​​わかりません。
neu242 2009

列挙では、理由のためにその特定の方法でエントリを注文したと想定されています。理由がない場合は、<enum> .toString()。compareTo()を使用することをお勧めします。それとも、セットのように、まったく異なる何かでしょうか?
ボンベ、

これが発生した理由は、{isocode、countryname}のEnumがあるためです。意図したとおりに機能する国名で手動でソートされました。今後、isocodeでソートする場合はどうなりますか?
neu242 2009
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.