2010-09-17 45 views
36

Giả sử bạn có một tập tin văn bản như:Java: instantiating một enum sử dụng phản ánh

my_setting = ON 
some_method = METHOD_A 
verbosity = DEBUG 
... 

đó bạn muốn cập nhật một đối tượng tương ứng cho phù hợp:

Setting my_setting = ON; 
Method some_method = METHOD_A; 
Verbosity verbosity = DEBUG; 
... 

đâu tất cả đều loại khác nhau của enums .

Tôi muốn có một cách chung để khởi tạo các giá trị enum. Đó là, tại thời gian chạy sử dụng sự phản chiếu, và không biết trước các loại enum của đối tượng.

Tôi cũng nghĩ tới một cái gì đó như thế này:

for (ConfigLine line : lines) 
{ 
    String[] tokens = line.string.split("=", 2); 
    String name = tokens[0].trim(); 
    String value = tokens[1].trim(); 

    try 
    { 
     Field field = this.getClass().getDeclaredField(name); 
     if(field.getType().isEnum()) 
     { 
     // doesn't work (cannot convert String to enum) 
     field.set(this, value); 
     // invalid code (some strange generics issue) 
     field.set(this, Enum.valueOf(field.getType().getClass(), value)); 
     } 
     else 
     { /*...*/ } 
    } 
    catch //... 
} 

Câu hỏi đặt ra là: những gì nên có thể thay thế? Thậm chí có thể tạo ra một enum không xác định cho biểu diễn chuỗi của nó không?

Trả lời

80
field.set(this, Enum.valueOf((Class<Enum>) field.getType(), value)); 
  • getClass() sau getType() không nên được gọi là - nó trả về lớp của một Class Ví dụ
  • Bạn có thể truyền Class<Enum>, để tránh các sự cố chung, vì bạn đã biết rằng Classenum
+0

Phunky! (8 nhiều hơn để đi) –

+0

kết quả này trong một lỗi trình biên dịch generics: Phương pháp valueOf (Class , String) trong loại Enum không áp dụng cho các đối số (Class , Object) – onejigtwojig

+0

Trình biên dịch nào? .. – Bozho

4

Bạn có thêm một getClass cuộc gọi, và bạn phải cast (cast cụ thể hơn mỗi Bozho):

field.set(test, Enum.valueOf((Class<Enum>) field.getType(), value)); 
+1

vấn đề Generics vẫn xảy ra – Bozho

0

Bạn có thể mã Enum của bạn tương tự tho này:

public enum Setting { 

    ON("ON"),OFF("OFF"); 

    private final String setting; 

    private static final Map<String, Setting> stringToEnum = new ConcurrentHashMap<String, Setting>(); 
    static { 
     for (Setting set: values()){ 
      stringToEnum.put(set.setting, set); 
     } 
    } 

    private Setting(String setting) { 
     this.setting = setting; 
    } 

    public String toString(){ 
     return this.setting; 
    } 

    public static RequestStatus fromString(String setting){ 
     return stringToEnum.get(setting); 
    } 
} 

Sau đó, bạn có thể dễ dàng tạo ra Enum từ String mà không cần suy nghĩ:

Setting my_settings = Setting.fromString("ON"); 

Giải pháp này không có nguồn gốc từ bản thân mình. Tôi đọc nó từ nơi khác, nhưng tôi không thể nhớ lại nguồn.

+0

Không thực sự hữu ích nếu bạn đang sử dụng sự phản chiếu, bởi vì bạn không biết nếu enum được đề cập đang sử dụng thiết lập này chưa. – Kolky

2

giải pháp thay thế không có đúc

try { 
    Method valueOf = field.getType().getMethod("valueOf", String.class); 
    Object value = valueOf.invoke(null, param); 
    field.set(test, value); 
} catch (ReflectiveOperationException e) { 
    // handle error here 
} 
0

Kết quả trả lời được chấp nhận trong các cảnh báo vì nó sử dụng các loại nguyên Enum thay vì Enum < T kéo dài Enum <T> >.

Để làm được việc này bạn cần phải sử dụng một phương pháp chung chung như thế này:

@SuppressWarnings("unchecked") 
private <T extends Enum<T>> T createEnumInstance(String name, Type type) { 
    return Enum.valueOf((Class<T>) type, name); 
} 

Gọi nó như thế này:

Enum<?> enum = createEnumInstance(name, field.getType()); 
field.set(this, enum); 
Các vấn đề liên quan