2016-08-29 9 views
6

Tôi có một số enums có thể được tìm thấy bởi một int. Điều này được thực hiện bằng một phương thức tĩnh trên enum. Ví dụ:Phương pháp tĩnh trong giao diện không hoạt động, làm thế nào để có được giá trị enum cụ thể từ một số enums?

enum Foo { 
A, B, C, D, ... ; 
    public static Foo fromInt(int i) { 
    switch(i) { 
    case 15: return A; 
    case 42: return B; 
    ... 
} 
} 
enum Bar { 
BLA, BOO, BEE, ... ; 
    public static Bar fromInt(int i) { 
    switch(i) { 
    case 78: return BLA; 
    case 22: return BOO; 
    ... 
} 
} 
... 

Bây giờ trong một số mã tôi có một kiểu generic T mà được đảm bảo là một trong những sự đếm và tôi có một số nguyên i. Làm thế nào tôi có thể gọi phương thức fromInt và nhận được cá thể của enum theo giá trị i?

Tôi đã thử tạo giao diện với phương thức tĩnh fromInt và để enums triển khai, nhưng các phương thức tĩnh không hoạt động trong giao diện.

tôi không thể sử dụng Java 8. Câu trả lời

+0

Còn phản ánh thì sao? –

+0

Vì vậy, bạn có một biến 'Class ' ở đâu đó, đúng không? Bạn có thể cung cấp mã của bạn với loại chung này không? – sp00m

+2

Bạn có chắc chắn rằng các tập hợp các giá trị 'int' trong' Foo' và 'Bar' được phân tách không? – bradimus

Trả lời

2

ngắn bạn không thể

Long trả lời bạn có thể vượt qua Class của enum rằng phương pháp của bạn và gọi fromInt bởi sự phản ánh hoặc tạo giao diện nhà máy và implent nó cho mỗi enum của bạn sau đó vượt qua đúng dụ để phương pháp của bạn.

0

Mở rộng @talex's answer:

Reflection:

public class YourEnumFactory { 

    public static <T extends Enum<T>> T get(Class<T> type,int i) { 
    try { 
     return (T) type.getDeclaredMethod("fromInt", int.class).invoke(null, i); 
    } catch (Exception e) { 
     throw new IllegalStateException("Could not find instance of '" + type + "' given '" + i + "'", e); 
    } 
    } 

} 

nhà máy:

public class YourEnumFactory { 

    private interface Factory<T> { 
    T fromInt(int i); 
    } 

    private static final Map<Class<?>, Factory<?>> FACTORIES; 
    static { 
    Map<Class<?>, Factory<?>> factories = new HashMap<>(); 
    factories.put(Foo.class, new Factory<Foo>() { 

     @Override 
     public Foo fromInt(int i) { 
     return Foo.fromInt(i); 
     } 

    }); 
    factories.put(Bar.class, new Factory<Bar>() { 

     @Override 
     public Bar fromInt(int i) { 
     return Bar.fromInt(i); 
     } 

    }); 
    FACTORIES = Collections.unmodifiableMap(factories); 
    } 

    public static <T extends Enum<T>> T get(Class<T> type, int i) { 
    Factory<T> factory = (Factory<T>) FACTORIES.get(type); 
    if (factory != null) { 
     return factory.fromInt(i); 
    } else { 
     throw new InvalidParameterException("No factory for type '" + type + "'"); 
    } 
    } 

} 

Như tôi đã luôn cố gắng để tránh phản chiếu, cá nhân tôi sẽ chọn giải pháp thứ hai.

0

Bạn không thể làm điều đó như thế, nhưng tôi sẽ làm điều đó như thế này:

interface HasId() { 
    public int getId(); 
} 

public class MyRegistry { 
    private static Map<Class<?>, Map<Integer, Object>> REGISTRY = new HashMap<>(); 
    public static <T extends HasId> T fromInt(int id, Class<T> clazz) { 
     return clazz.cast(REGISTRY.getOrDefault(clazz, Collections.emptyMap()).get(id)); 
    } 
    public static void register(HasId obj) { 
     REGISTRY.putIfAbsent(obj.getClass(), new HashMap<>()).put(obj.getId, obj); 
    } 
} 

enum Foo implements HasId { 
    A(15), B(42), C(86), D(99); 
    private final int id; 
    Foo(int id) { 
     this.id = id; 
     MyRegistry.register(this); 
    } 
    public int getId() { 
     return id; 
    } 
} 
// ditto for other enums or non enums as you like 

Sau đó, để sử dụng:

Foo foo = MyRegistry.fromInt(15, Foo.class); // A 

Disclaimer: Mã có thể không biên dịch hoặc làm việc vì nó đã được bật lên trên điện thoại của tôi (nhưng có một cơ hội hợp lý nó sẽ hoạt động)

+0

Lưu ý rằng 'putIfAbsent' không hoạt động theo cách bạn mong đợi (không giống như' computeIfAbsent'). 'putIfAbsent' luôn trả về giá trị cũ, tức là' null' nếu không có ánh xạ trước đó và giá trị trước đó (vẫn hiện diện) khác. Hơn nữa, nó không giúp sử dụng một bản đồ an toàn cho luồng, khi nó được chứa không an toàn 'Bộ' được truy cập mà không có bất kỳ sự bảo vệ nào. – Holger

+0

Ngoài ra, mã dựa vào việc khởi tạo lớp của loại 'enum' thực tế không được bảo đảm. Mặt khác, nó sẽ dễ dàng để cho 'fromInt' lặp lại các giá trị enum một cách phản ánh, loại bỏ sự cần thiết phải đăng ký. – Holger

+0

@Holger Không phải khởi tạo enum được đảm bảo do lớp học được truyền vào cuộc gọi? – Bohemian

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