2011-12-28 24 views
5

Tôi cố gắng để làm reverse lookup trên vài lớp enum thực hiện chuyển đổi giao diện Field bằng cách duyệt qua danh sách các Class es sử dụng ổi của Maps.uniqueIndex:Sử dụng Generics với bộ sưu tập của các lớp enum thực hiện chuyển đổi giao diện

Field valueOfSearchName = null; 
    for (final Class<? extends Enum<?>> clazz : ImmutableList.of(
     EntityField.class, 
     AddressField.class, 
     PersonFunctionType.class)) { 
    valueOfSearchName = Fields.valueOfSearchName(clazz, term.field()); // error 
    if (valueOfSearchName != null) { 
     // do something... 
     break; 
    } 
    } 

Tôi không muốn để lặp lại cùng một mã (để làm chỉ mục và làm tra cứu) trong mọi tầng lớp enum, vì vậy tôi sử dụng helper tĩnh lớp Fields chứa Fields.valueOfSearchName phương pháp:

public static <E extends Enum<E> & Field> Field valueOfSearchName(
     final Class<E> clazz, final String searchName) { 
    // TODO: cache the index 
    final ImmutableMap<String, E> index = Maps.uniqueIndex(
     EnumSet.allOf(clazz), GET_SEARCH_NAME_FUNCTION); 
    return index.get(searchName); 
    } 

Thật không may, Eclipse cho thấy một lỗi:

Bound mismatch: 
The generic method valueOfSearchName(Class<E>, String) of type Fields is not 
applicable for the arguments (Class<capture#1-of ? extends Enum<?>>, String). 
The inferred type capture#1-of ? extends Enum<?> is not a valid substitute 
for the bounded parameter <E extends Enum<E> & Field> 

Vấn đề là Class<? extends Enum<?>> clazz trong for-each vòng lặp (không phù hợp với Field), nhưng tôi không biết làm thế nào để đối phó với trường hợp này (rõ ràng là tôi không thể thêm & Field đến clazz).

+0

Liên kết này có thể hữu ích http://stackoverflow.com/questions/7032941/why-is-this-type-not-a-valid-substitute-for-the-type-parameter – kosa

+1

Eclipse nổi tiếng vì không đồng ý với thông thường. Kiểm tra bài đăng này: http://stackoverflow.com/questions/2220763/java-specific-enums-and-generic-enum-parameters –

+0

@baba Tôi không thể thay thế ký tự đại diện '?' Bằng thông số loại có tên 'T' trong vòng lặp for-each, nơi xảy ra sự cố ... Tuy nhiên [lấy cảm hứng từ câu trả lời của John Skeet từ câu hỏi này] (http://stackoverflow.com/questions/5262096/how-do-i-get-the-value-of -an-enum-if-i-dont-know-the-class-at-biên dịch-thời gian) Tôi thay đổi vòng lặp để 'cho (@SuppressWarnings (" rawtypes ") cuối cùng Class clazz: ...' và nó đã làm các trick ...Có đúng cách để làm điều này không? – Xaerxess

Trả lời

0

Lấy cảm hứng từ Tom Hawtin's answer Tôi tạo ra lớp wrapper giữ Class es, nhưng chỉ những người có chữ ký <E extends Enum<E> & Field>:

public final static class FieldEnumWrapper<E extends Enum<E> & Field> { 
    private final Class<E> clazz; 
    private final ImmutableMap<String, E> index; 

    public static <E extends Enum<E> & Field> 
     FieldEnumWrapper<E> of(final Class<E> clazz) { 
    return new FieldEnumWrapper<E>(clazz); 
    } 

    private FieldEnumWrapper(final Class<E> clazz) { 
    this.clazz = clazz; 
    this.index = Maps.uniqueIndex(
     EnumSet.allOf(clazz), new Function<E, String>() { 
      @Override 
      public String apply(final E input) { 
      return input.searchName(); 
      } 
     }); 
    } 

    public Class<E> clazz() { 
    return clazz; 
    } 

    public Field valueOfSearchName(final String searchName) { 
    return index.get(searchName); 
    } 
} 

Bây giờ là:

for (final FieldEnumWrapper<?> fieldEnum : ImmutableList.of(
    FieldEnumWrapper.of(EntityField.class), 
    FieldEnumWrapper.of(AddressField.class), 
    FieldEnumWrapper.of(PersonFunctionType.class))) { 
    valueOfSearchName = fieldEnum.valueOfSearchName("POD_I_OS_PARTNER"); 
    // ... 

là loại an toàn sử dụng không phù hợp của nhà máy tĩnh FieldEnumWrapper 's:

FieldEnumWrapper.of(NotEnumAndFieldClass.class) 

tạo biên dịch lỗi.

Hơn nữa, valueOfSearchName hiện là phương pháp FieldEnumWrapper điều gì có ý nghĩa hơn là lớp trợ giúp.

3

Cân nhắc Class<? extends List<?>. Class<? extends List<?> có hai ký tự đại diện trong khi <E extends List<E>> Class<E> chỉ có thông số chung. Người trước sẽ thừa nhận Class<ArrayList<String>>. Vì vậy, mà không làm một cái gì đó thêm đặc biệt cho enums, các loại không tương thích.

Cách khắc phục? Một lớp bổ sung của indirection!

public final class MetaEnum<E extends Enum<E>> { 
    private final E clazz; 
    public static <E extends Enum<E>> MetaEnum<E> of(E clazz) { 
     return clazz; 
    } 
    private MetaEnum(E clazz) { 
     this.clazz = clazz; 
    } 
    public E clazz() { 
     return clazz; 
    } 
    // ... 
} 

for (final MetaEnum<?> meta : ImmutableList.of(
    MetaEnum.of(EntityField  .class), 
    MetaEnum.of(AddressField  .class), 
    MetaEnum.of(PersonFunctionType.class) 
)) { 
    Field valueOfSearchName = Fields.valueOfSearchName(
     meta.clazz(), term.field() 
    ); 
    ... 

(thông thường Stack Overflow dislaimer:. Không phải như vậy nhiều càng cố gắng để biên dịch)

0

có lẽ một cái gì đó như thế này:

import java.util.*; 
class N { 
    static int n; 
} 
interface HasField { 
    int getField(); 
} 
enum Color implements HasField { 
    r, g, b; 
    public int getField() { 
     return field; 
    } 
    private int field = N.n++; 
} 
enum Day implements HasField { 
    m, t, w, th, f, sa, su; 
    public int getField() { 
     return field; 
    } 
    private int field = N.n++; 
} 
    class Helper { 
    Helper(Set<HasField> set) { 
     for (HasField hasField : set) 
      if (hasField instanceof Enum) { 
       Enum<?> e = (Enum<?>) hasField; 
       for (Object o : e.getDeclaringClass().getEnumConstants()) { 
        map.put(((HasField) o).getField(), (Enum<?>) o); 
       } 
      } else 
       throw new RuntimeException(hasField + " is not an enum!"); 
    } 
    final Map<Integer, Enum<?>> map = new TreeMap<Integer, Enum<?>>(); 
} 
public class Main { 
    public static void main(String[] args) { 
     Set<HasField> set = new LinkedHashSet<HasField>(); 
     set.add(Color.r); 
     set.add(Day.m); 
     Helper helper = new Helper(set); 
     for (int i = 0; i < N.n; i++) 
      System.out.println(i + " " + helper.map.get(i)); 
    } 
} 
+0

Tạo tập hợp các phần tử intstead của các lớp và sự kết hợp của 'e.getDeclaringClass(). getEnumConstants()' cùng với 'Enum <-> phôi của HasField' không thể đọc được và không an toàn kiểu nào cả ... Và cũng' set.add (new HasField() {public int getField() {return 42;}}); 'là một classCastException thời gian chạy. – Xaerxess

+0

đã thêm một thử nghiệm: instanceFieldFile của Enum –

+0

Tuy nhiên, tôi thích ngoại lệ thời gian biên dịch hơn là thời gian chạy;) – Xaerxess

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