CompareTo neden Java'da bir Enum finalinde?


96

Java'daki bir enum Comparablearabirimi uygular . Comparable'In compareToyöntemini geçersiz kılmak güzel olurdu , ama burada son olarak işaretlendi. Enum'Ler compareToiçin varsayılan doğal sıra , listelenen sıradır.

Java numaralarının neden bu kısıtlamaya sahip olduğunu bilen var mı?


Etkili Java - 3. Baskı'da Madde 10'da çok güzel bir açıklama var (eşittir () ile ilgileniyorlar, ancak Madde 14'te Karşılaştırma () ile Sorunun aynı olduğunu söylüyorlar). Kısaca: Örneklenebilir bir sınıfı (enum gibi) genişletirseniz ve bir değer bileşeni eklerseniz, eşittir (veya CompareTo) sözleşmesini koruyamazsınız.
Christian H. Kuhn

Yanıtlar:


122

Tutarlılık için sanırım ... bir enumtür gördüğünüzde , bir gerçeği biliyorsunuz doğal sipariş sabitleri beyan edildiği düzeni olduğunu.

Bunu geçici olarak çözmek için, kolayca kendi Comparator<MyEnum>siparişinizi oluşturabilir ve farklı bir siparişe ihtiyaç duyduğunuzda kullanabilirsiniz:

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

ComparatorDoğrudan kullanabilirsiniz :

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

veya koleksiyonlarda veya dizilerde kullanın:

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

Daha fazla bilgi:


Özel karşılaştırıcılar yalnızca Enum'u bir Koleksiyona sağlarken gerçekten etkilidir. Doğrudan bir karşılaştırma yapmak istemeniz o kadar yardımcı olmuyor.
Martin OConnor

7
Evet öyle. yeni MyEnumComparator.compare (enum1, enum2). Et voilá.
Bombe

@martinoconnor & Bombe: Yorumlarınızı yanıta ekledim. Teşekkürler!
Zach Scrivena

Yana MyEnumComparatorhiçbir durumu vardır, sadece sen @Bombe önerdiklerini yapıyoruz, özellikle bir tekil olmalıdır; bunun yerine MyEnumComparator.INSTANCE.compare(enum1, enum2)gereksiz nesne oluşturmayı önlemek için bir şeyler yaparsınız
kbolino

2
@kbolino: Karşılaştırıcı olay, enum sınıfı içinde yuvalanmış bir sınıf olabilir. LENGTH_COMPARATORNumaralandırmada statik bir alanda depolanabilir . Bu şekilde, numaralandırmayı kullanan herkes için bulmak kolay olacaktır.
Lii

40

Karşılaştırma için kaynak kodu sıralaması kullanan varsayılan bir uygulama sağlamak iyidir; final yapmak Sun için bir yanlış adımdı. Sıra zaten bildirim sırasını hesaba katıyor. Çoğu durumda bir geliştiricinin öğelerini mantıksal olarak sıralayabileceğini kabul ediyorum, ancak bazen kaynak kodun okunabilirliği ve bakımı en önemli hale getirecek şekilde düzenlenmesini istiyor. Örneğin:


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

Yukarıdaki sıralama, kaynak kodda iyi görünüyor, ancak yazar, CompareTo'nun çalışması gerektiğine inanmıyor. Arzu edilen CompareTo davranışı, sıralamanın bayt sayısına göre olmasıdır. Bunun gerçekleşmesini sağlayacak kaynak kodu sıralaması, kodun organizasyonunu bozar.

Bir numaralandırma müşterisi olarak yazarın kaynak kodunu nasıl düzenlediğini daha az umursayamazdım. Yine de karşılaştırma algoritmalarının bir anlam ifade etmesini istiyorum. Sun, kaynak kodu yazarlarını gereksiz yere zor durumda bıraktı.


4
Katılıyorum, numaramın, birisi dikkat etmezse kırılabilecek bir sipariş yerine işle benzer bir algoritmaya sahip olmasını istiyorum.
TheBakker

6

Numaralandırma değerleri, bildirildikleri sıraya göre tam olarak mantıksal olarak sıralanır. Bu, Java dili belirtiminin bir parçasıdır. Bu nedenle, numaralandırma değerlerinin yalnızca aynı Enum'un üyeleriyse karşılaştırılabileceğini izler. Spesifikasyon, ayrıca ComparTo () tarafından döndürülen karşılaştırılabilir sıranın, değerlerin bildirildiği sırayla aynı olduğunu garanti etmek ister. Bu, bir numaralandırmanın tam tanımıdır.


Thomas Paine'in örneğinde açıkladığı gibi, dil yalnızca sözdizimsel olarak düzenlenebilir, anlambilimle değil. Öğeler mantıksal olarak sıralanır diyorsunuz, ancak numaralandırmayı anladığım kadarıyla, öğeler mantıksal araçlarla kapsüllenir .
Bondax

2

Olası bir açıklama olduğunu compareTotutarlı olmalıdırequals .

Ve equalsnumaralandırmalar için kimlik eşitliği ile tutarlı olmalıdır (== ) .

Eğer compareTosigara nihai olarak nereye tutarlı olmayan bir davranış ile geçersiz kılmak mümkün olacağını equalsçok karşı-sezgisel olacaktır.


CompareTo () işlevinin equals () ile tutarlı olması tavsiye edilse de gerekli değildir.
Christian H. Kuhn

-1

Numaralandırmanızın öğelerinin doğal sırasını değiştirmek istiyorsanız, kaynak kodundaki sıralarını değiştirin.


Evet, orijinal girişte yazdığım
buydu

Evet, ancak ComparTo () öğesini neden geçersiz kılmak istediğinizi gerçekten açıklamıyorsunuz. Benim sonucum, Something Bad ™ yapmaya çalıştığın ve ben de sana daha doğru bir yol göstermeye çalıştığım oldu.
Bombe

Bilgisayarlar bunu benden çok daha iyi yaptığında neden girdileri elle sıralamak zorunda olduğumu anlamıyorum.
neu242

Numaralandırmalarda, girişleri bir nedenden ötürü belirli bir şekilde sipariş ettiğiniz varsayılır. <enum> .toString (). CompareTo () kullanarak daha iyi durumda olmanın bir nedeni yoksa. Ya da belki bir Set gibi tamamen farklı bir şey?
Bombe

Bunun ortaya çıkmasının nedeni, {isocode, countryname} içeren bir Enum'a sahip olmam. İstendiği gibi çalışan ülke adına göre manuel olarak sıralandı. Bundan sonra izo koduna göre sıralamak istediğime karar verirsem ne olur?
neu242
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.