2010-10-25 32 views
26

Tôi đang cố gắng giải quyết một lỗi biên dịch ("Bound mismatch: ...") liên quan đến tra cứu enum động.Enum.valueOf (Class <T> enumType, String name) question

Về cơ bản tôi muốn đạt được một cái gì đó như thế này:

String enumName = whatever.getEnumName(); 
Class<? extends Enum<?>> enumClass = whatever.getEnumClass(); 
Enum<?> enumValue = Enum.valueOf(enumClass, enumName); 

Dù tôi làm, tôi luôn kết thúc với rằng lỗi biên dịch. Thành thật mà nói, generics và enums khá mindboggling với tôi ...

Tôi đang làm gì sai ở đây?

Trả lời

22

Tôi nghĩ rằng nó sẽ không hoạt động chính xác như thế này trừ khi bạn có quyền truy cập vào một biến kiểu (thông qua một loại hoặc chữ ký phương thức). Vấn đề là chữ ký phương thức của Enum.valueOf:

public static <T extends Enum<T>> T valueOf(
    Class<T> enumType, 
    String name 
); 

Không có cách nào để lấy T mà không có biến số. Nhưng bạn có thể làm điều đó như thế này nếu bạn sẵn sàng để ngăn chặn một số cảnh báo trình biên dịch:

public enum King{ 
    ELVIS 
} 

@SuppressWarnings({ "unchecked", "rawtypes" }) 
public static void main(final String[] args){ 
    final Class<? extends Enum> enumType = King.class; 
    final Enum<?> theOneAndOnly = Enum.valueOf(enumType, "ELVIS"); 
    System.out.println(theOneAndOnly.name()); 
} 

Output:

ELVIS

+0

Câu hỏi đặt ra là về enums, Generics và phản ánh. Nếu bạn bỏ qua Generics Đặc biệt là cho "loại hiếm" như 'Lớp ' –

+2

Vấn đề là a) nó không thể hoạt động nếu không có phương thức trợ giúp hoặc kiểu và b) chúng ta biết chắc chắn rằng 'Lớp 'cũng sẽ thỏa mãn' Lớp > '(vì đó là cách các lớp enum hoạt động) mặc dù không có cách nào để kiểm tra mà không có biến kiểu. '@ SuppressWarnings' là chú thích bạn chỉ nên sử dụng nếu bạn biết mình đang làm gì và tôi biết. –

19

Vấn đề là với Class<? extends Enum<?>>. Chúng tôi muốn E extends Enum<E>, nhưng chúng tôi không thể có được điều đó bởi vì chúng tôi có hai ký tự đại diện riêng biệt.

Vì vậy, chúng ta cần phải đưa ra một thông số chung chung, có thể giới thiệu bằng cách gọi một phương pháp:

enum MyEnum { 
    ME; 
} 

public class EnName { 
    public static void main(String[] args) { 
     Enum<?> value = of(MyEnum.class, "ME"); 
     System.err.println(value); 
    } 
    private static <E extends Enum<E>> E of(Class<E> clazz, String name) { 
     E value = Enum.valueOf(clazz, name); 
     return value; 
    } 
} 

Nhưng phản ánh là dơ dáy và rất hiếm khi những gì bạn muốn. Đừng làm thế.

+1

Cảm ơn lời giải thích này, nó đã giúp rất nhiều để hiểu thêm những gì đang xảy ra. Vì trong trường hợp sử dụng cụ thể của tôi, tôi không có bất cứ điều gì để cung cấp như là tham số chung, tôi sẽ đi cho câu trả lời của seanizer. – Tom

6

Có thực sự là một cách tiếp cận thay thế: bạn có thể sử dụng Class.getEnumConstants và cuộn triển khai của riêng bạn Enum.valueOf không có cùng vấn đề về loại. Nhược điểm là bạn lấy lại một số chung là Enum<?> - nhưng nếu bạn biết bạn đã nhập loại gì, bạn vẫn có thể sử dụng Enum.valueOf.

private static Enum<?> findEnumValue(Class<? extends Enum<?>> enumType, String value) { 
    return Arrays.stream(enumType.getEnumConstants()) 
       .filter(e -> e.name().equals(value)) 
       .findFirst() 
       .orElse(null); 
} 

(Lưu ý rằng phiên bản của tôi trả null nếu không có như vậy liên tục thay vì ném một IllegalArgumentException, nhưng đó là một điều tầm thường để thay đổi.

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