2010-06-18 29 views
12

Xin xem Java Enum definitionWhy in java enum is declared as Enum<E extends Enum<E>> để thảo luận chung. Ở đây tôi muốn tìm hiểu chính xác những gì sẽ được chia (không an toàn kiểu nữa, hoặc yêu cầu phôi thêm vv) nếu lớp Enum được định nghĩa làĐiều gì sẽ là khác nhau trong Java nếu khai Enum không có phần đệ quy

public class Enum<E extends Enum> 

Tôi đang sử dụng mã này để thử nghiệm ý tưởng của tôi:

interface MyComparable<T> { 
    int myCompare(T o); 
} 

class MyEnum<E extends MyEnum> implements MyComparable<E> { 
    public int myCompare(E o) { return -1; } 
} 

class FirstEnum extends MyEnum<FirstEnum> {} 

class SecondEnum extends MyEnum<SecondEnum> {} 

Tôi không thể tìm thấy bất kỳ lợi ích nào trong trường hợp chính xác này.

PS. thực tế là tôi không được phép để làm

class ThirdEnum extends MyEnum<SecondEnum> {} 

khi MyEnum được định nghĩa với đệ quy là
a) không có liên quan, bởi vì với sự đếm thực bạn không được phép để làm điều đó chỉ vì bạn không thể mở rộng enum chính mình
b) không đúng - hãy thử nó trong trình biên dịch và thấy rằng thực tế có thể biên dịch w/o bất kỳ lỗi nào

PPS. Tôi ngày càng có khuynh hướng tin rằng câu trả lời đúng ở đây sẽ là "không có gì thay đổi nếu bạn loại bỏ phần đệ quy" - nhưng tôi không thể tin được.

Trả lời

1

Tôi tin rằng một lý do thuyết phục để làm điều đó là nó làm cho mã trong lớp MyEnum an toàn hơn.

Hãy xem xét rằng phần đệ quy làm một điều như vậy có thể:

class MyEnum<E extends MyEnum<E>> { 
    private Thing<E> util1() { return someObject } 
    private void util2(E e) {} 
    public int method(E o) { 
     Thing<E> thingy = o.util1(); 
     // You can call the util1 method on o and get a type safe return element. 
     E o1 = // I don't care how you get a parametrized E object. 
     o.util2(o1); 
     // You can call the util2 method with a typesafe parameter. 
    } 
} 

Nói tóm lại, đệ quy cho phép bạn đặt các phương pháp typesafe trong lớp Enum rằng bạn có thể gọi vào bất kỳ yếu tố E, và các cuộc gọi sẽ an toàn.

+1

chỉ là một lưu ý nhỏ, 'o.util2 (this)' sẽ không biên dịch vì đây được coi là MyEnum không E. Bạn có thể thêm tham số thứ hai 'E o1' và gọi' o.util2 (o1) 'mặc dù cho cùng một hiệu ứng: nó sẽ biên dịch với 'E mở rộng MyEnum ', nhưng không phải với 'E mở rộng MyEnum ' –

+0

Cảm ơn bạn, tôi vừa sửa lỗi đó. –

+0

cảm ơn bạn! mã đó thực sự được đánh dấu là không an toàn nếu bạn loại bỏ đệ quy! Bạn có biết cách sử dụng thực tế của tính năng đó trong jdk không? – atamur

1

Cân nhắc Enum<E>.compareTo(E other).

Đó:

  • nhu cầu làm việc với E chứ không phải là enum để bạn không nên cố gắng để so sánh một giá trị enum với một giá trị từ một enum khác nhau
  • nhu cầu để có thể có được thứ tự giá trị của enum, thông qua phương thức ordinal()được khai báo trên Enum.

Bạn sẽ đề xuất việc đó như thế nào mà không có ràng buộc hiện tại?

Đó chỉ là lần đầu tiên tôi đưa ra ... Tôi chắc rằng có rất nhiều người khác. Về cơ bản nó là một cách để nói, "Bạn không nên cố gắng đối xử với tất cả các enums tương đương với nhau ... một enum là một bộ đóng trong chính nó, nhưng tất cả enums chia sẻ tài sản nhất định."

+0

compareTo - xem qn của tôi. Theo cách đó, nó hoạt động chính xác như bạn nói. W/o bất kỳ đệ quy nào. Không thấy một vấn đề với thứ tự hoặc - bạn có thể cung cấp một số mã phá vỡ/không an toàn không? – atamur

+0

@atamur: Tôi đã không chú ý đến loại bit thô trong ví dụ của bạn (bạn đã chỉnh sửa trong vòng năm phút đầu tiên sau khi hỏi? Có lẽ tôi chỉ đọc nhầm nó). Thực tế là bạn cần một loại nguyên ngay lập tức làm cho tôi lo lắng, phải trung thực ... –

+0

Nếu thứ tự là lý do, sau đó 'lớp Enum >' sẽ là đủ. – newacct

2

Vâng, trước hết nó sẽ phàn nàn về việc sử dụng các loại nguyên liệu, nhưng bạn có thể làm:

public class Enum<E extends Enum<?>> 

cho tác dụng tương tự.

Ngoài ra, với kiểu này chung bạn có thể làm một cái gì đó như:

class FirstEnum extends MyEnum<SecondEnum> { 
} 

class SecondEnum extends MyEnum<FirstEnum> { 
} 

mà với tôi có vẻ như nó có thể dẫn đến rất nhiều rắc rối. Chính xác hơn bạn không thể so sánh một enum kiểu FirstEnum với một enum cùng loại, bạn phải so sánh nó với một enum của kiểu khác, điều này thực sự phiền hà nếu bạn có một List<FirstEnum> mà bạn muốn sắp xếp.Ví dụ sẽ không biên dịch nếu tôi đặt E thay vì o ? vì SecondEnum không thuộc loại E extends MyEnum<E> (điều này sẽ dẫn đến kế thừa tròn). Nó sẽ làm việc nếu FirstEnum extends MyEnum<FirstEnum> mặc dù (có nghĩa là SecondEnum là một lớp con của FirstEnum - thừa kế phân cấp bình thường).

+0

Loại thô có vẻ thú vị - nhưng javac không phát ra bất kỳ cảnh báo thô nào nếu bạn thực sự thử. hãy xem ps của tôi trong qn. Có 2 điểm tại sao điều này không liên quan. – atamur

+1

Tôi đang sử dụng nhật thực và nó đưa ra cảnh báo về loại thô (chưa kể rằng mặt trời đã nói rằng chúng ta không nên sử dụng các loại thô nữa). Có lẽ javac yêu cầu một số loại tùy chọn được kích hoạt để phàn nàn về điều này? –

+1

Ngoài ra, điểm thứ hai của ps là không đúng đối với ví dụ của tôi, nếu tôi đặt lớp thành 'public class MyEnum >' nó không biên dịch. Về điểm đầu tiên, tôi nghĩ rằng nó có thể tạo ra tệp .class sao cho nó có ký hiệu phương thức giống như các lớp được viết như thế này (bằng cách sử dụng một trình biên dịch không chuẩn) mặc dù javac sẽ không cho phép bạn biên dịch ' public enum FirstEnum mở rộng MyEnum 'hoặc một cái gì đó tương tự. –

0

Nếu bạn không có thông số loại chung, thì bạn sẽ không thể mở rộng Comparable<T extends Comparable> cho loại phụ cụ thể của enum mà bạn đã tạo.

Bạn có thể bỏ qua điều này, và tạo kiểu MyEnum của riêng bạn mà hành xử rất giống nhau nhưng nếu không có sự hạn chế đó MyEnum khác nhau là không thể so sánh:

public abstract class MyEnum implements Comparable<MyEnum> 
{ 
    private final int ordinal; 

    protected MyEnum (int ordinal) 
    { 
     this.ordinal = ordinal; 
    } 

    public int ordinal() 
    { 
     return ordinal ; 
    } 

    public int compareTo (MyEnum other) 
    { 
     return ordinal - other.ordinal; // ignore overflow for now 
    } 

    public boolean equals (Object other) { 
     return ordinal == ((MyEnum)other).ordinal; 
    } 

    public int hashCode() { 
     return ordinal; 
    } 
} 

này hoạt động theo cách tương tự như một enum sẽ cho các hoạt động được xác định, nhưng thay vì là một loại thực hiện an toàn chung tuân theo LSP - các đối tượng của các lớp con khác nhau của MyEnum có thể so sánh hoặc bằng nhau nếu chúng có cùng giá trị thứ tự.

public static class EnumA extends MyEnum 
{ 
    private EnumA (int ordinal) { super (ordinal); } 
    public static final EnumA a = new EnumA (0); 
    public static final EnumA b = new EnumA (1); 
} 

public static class EnumB extends MyEnum 
{ 
    private EnumB (int ordinal) { super (ordinal); } 
    public static final EnumB x = new EnumB (0); 
    public static final EnumB y = new EnumB (1); 
} 

public static void main (String...args) 
{ 
    System.out.println (EnumA.a.compareTo (EnumB.x)); 
    System.out.println (EnumA.a.equals (EnumB.x)); 
    System.out.println (EnumA.a.compareTo (EnumB.y)); 
    System.out.println (EnumA.a.equals (EnumB.y)); 
} 

Trong trường hợp này, nếu bạn không ghi đè equals, bạn sẽ mất công ước rằng x.comparesTo(y)=0 ngụ ý x.equals(y); nếu bạn ghi đè bằng thì có trường hợp x.equals(y) không ngụ ý x == y (đối với các đối tượng giá trị khác), trong khi đối với Java enums cả hai kiểm tra bình đẳng đều cho ra kết quả tương tự.

+0

Tôi e rằng bạn không hiểu qn của tôi. Nếu bạn nhìn vào mã của tôi - MyEnum đang sử dụng Generics, chỉ cần không phải là đệ quy bit. – atamur

0
`X extends Enum<Y>` 

sẽ là bất hợp pháp. rằng có liên quan. trình biên dịch có thể có các quy tắc đặc biệt với enum, nhưng tại sao không có khai báo loại hoàn hảo nếu có thể?

Các vấn đề liên quan