2009-02-06 8 views
72

Một enum trong Java thực hiện giao diện Comparable. Nó sẽ được tốt đẹp để ghi đè lên phương pháp compareTo của Comparable, nhưng ở đây nó được đánh dấu là cuối cùng. Đơn hàng tự nhiên mặc định trên Enum 's compareTo là thứ tự được liệt kê.Tại sao compareTo trên một Enum cuối cùng trong Java?

Có ai biết tại sao một enums Java có hạn chế này?

Trả lời

98

Để nhất quán, tôi đoán ... khi bạn thấy loại enum, bạn biết cho thực tế rằng thứ tự tự nhiên của nó là thứ tự các hằng số được khai báo.

Để workaround này, bạn có thể dễ dàng tạo riêng Comparator<MyEnum> của bạn và sử dụng nó bất cứ khi nào bạn cần một trật tự khác nhau:

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

Bạn có thể sử dụng Comparator trực tiếp:

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

hoặc sử dụng nó trong bộ sưu tập hoặc mảng:

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

Furth er thông tin:

+0

Các bộ so sánh tùy chỉnh chỉ thực sự hiệu quả khi cung cấp Enum cho Bộ sưu tập. Nó không giúp ích nhiều nếu bạn muốn so sánh trực tiếp. –

+5

Vâng, đúng vậy. new MyEnumComparator.compare (enum1, enum2). Et voilá. – Bombe

+0

@martinoconnor & Bombe: Tôi đã đưa ý kiến ​​của bạn vào câu trả lời. Cảm ơn! –

-2

Nếu bạn muốn thay đổi thứ tự tự nhiên của các yếu tố của enum, hãy thay đổi thứ tự của chúng trong mã nguồn.

+0

Yup, đó là những gì tôi đã viết trong mục gốc :) – neu242

+0

Có nhưng bạn không thực sự giải thích lý do bạn muốn ghi đè compareTo(). Vì vậy, kết luận của tôi là bạn đang cố gắng làm điều gì đó Bad ™ và tôi đã cố gắng để cho bạn thấy một cách chính xác hơn. – Bombe

+0

Tôi không hiểu tại sao tôi phải sắp xếp các mục nhập bằng tay khi máy tính làm tốt hơn tôi nhiều. – neu242

5

giá trị liệt kê được sắp xếp một cách chính xác một cách logic theo thứ tự mà chúng được khai báo. Đây là một phần của đặc tả ngôn ngữ Java. Do đó, nó chỉ có thể so sánh các giá trị liệt kê nếu chúng là thành viên của cùng một Enum. Đặc tả này muốn bảo đảm hơn nữa rằng thứ tự so sánh được trả về bởi compareTo() giống như thứ tự mà các giá trị được khai báo. Đây là định nghĩa của một điều tra.

+0

Như Thomas Paine đã làm rõ trong ví dụ của mình, ngôn ngữ chỉ có thể đặt theo cú pháp, chứ không phải ngữ nghĩa. Bạn nói, các mục được _ordered_ hợp lý, nhưng cách tôi hiểu enum, các mục được _encapsulated_ bằng các phương tiện logic. – Bondax

28

Cung cấp triển khai mặc định compareTo sử dụng thứ tự mã nguồn là tốt; làm cho nó cuối cùng là một sai lầm trên một phần của Sun. Thứ tự đã chiếm thứ tự khai báo. Tôi đồng ý rằng trong hầu hết các trường hợp, nhà phát triển chỉ có thể đặt hàng một cách hợp lý các yếu tố của họ, nhưng đôi khi người ta muốn mã nguồn được tổ chức theo cách giúp dễ đọc và bảo trì là tối quan trọng. Ví dụ:


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

Thứ tự trên có vẻ tốt trong mã nguồn nhưng không phải tác giả tin rằng compareTo hoạt động như thế nào. Hành vi compareTo mong muốn là đặt hàng theo số byte. Việc đặt mã nguồn sẽ làm cho điều đó xảy ra làm giảm sự tổ chức của mã.

Là khách hàng của một điều tra, tôi không thể quan tâm ít hơn cách tác giả đã tổ chức mã nguồn của họ. Tuy nhiên, tôi không muốn thuật toán so sánh của họ có ý nghĩa gì đó. Sun đã không cần thiết phải đưa các nhà văn mã nguồn vào một ràng buộc.

+3

Đồng ý, tôi muốn enum của tôi để có thể có một kinh doanh so sánh algorythm thay vì một trật tự có thể bị phá vỡ nếu ai đó không chú ý. – TheBakker

2

Một giải thích có thể là compareTo phải nhất quán với equals.

equals cho enums phải nhất quán với bình đẳng danh tính (==).

Nếu compareTo ở vị trí không cuối cùng, có thể ghi đè lên bằng hành vi không nhất quán với equals, điều này sẽ rất phản trực giác.