2014-10-17 2 views
4

Как я могу отличить Class<? extends Enum<?>> до Class<T>, где <T extends Enum<T>>? В частности, мне нужно передать экземпляр Class<? extends Enum<?>> методу Enum.valueOf(). http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#valueOf(java.lang.Class,%20java.lang.String)Правильно литые генераторы

Вот классы у меня есть:

enum Foo1 implements Bar { 
    VALUE1("A"), VALUE2("B"); 

    String me; 

    Foo1(String me) { 
    this.me = me; 
    } 

    String getMe() {return me;} 
} 

enum Foo2 implements Bar { 
    V1("A"), V2("B"); 

    String me; 

    Foo2(String me) { 
    this.me = me; 
    } 

    String getMe() {return me;} 
} 

interface Bar { 
    String getMe(); 
} 

enum Z { 
    Z1(Foo1.class), Z2(Foo2.class); 
    private final Class<? extends Enum<? extends Bar>> myEnum; 
    Z(Class<? extends Enum<? extends Bar>> myEnum) { 
    this.myEnum = myEnum; 
    } 

    Class<? extends Enum<? extends Bar>> getMyEnum() { 
    return myEnum; 
    } 
} 

class X { 
    public getMe(Z z, String fooValue) { 
     Class<? extends Enum<? extends Bar>> fooEnum = z.getMyEnum(); 
     // does not compile 
     return ((Bar)Enum.valueOf(fooEnum, fooValue)).getMe(); 
    } 
} 
+0

Кастинг небезопасный по своей природе. Можете ли вы показать нам, что вы пытаетесь сделать и почему? –

ответ

0

Самый простой способ сделать это, чтобы бросить к сырому типу Class:

return ((Bar)Enum.valueOf((Class)fooEnum, fooValue)).getMe(); 

Если вам не нравится проливает вы можете обернуть классы перечислений в другом классе, когда вы поместите их в Z, чтобы сохранить больше их отношения типов.

enum Z { 
    Z1(new Holder<>(Foo1.class)), Z2(new Holder<>(Foo2.class)); 
    private final Holder<?> myEnum; 

    Z(Holder<?> myEnum) { 
     this.myEnum = myEnum; 
    } 
    Holder<?> getMyEnumHolder() { 
     return myEnum; 
    } 

    static class Holder<T extends Enum<T> & Bar> { 
     private final Class<T> myEnum; 

     private Holder(Class<T> myEnum) { 
      this.myEnum = myEnum; 
     } 

     Class<T> getMyEnum() { 
      return myEnum; 
     } 
    } 
} 

class X { 
    public static String getMe(Z z, String fooValue) { 
     return Enum.valueOf(z.getMyEnumHolder().getMyEnum(), fooValue).getMe(); 
    } 
} 
0

Вот один из способов сделать это

class X { 
    @SuppressWarnings("unchecked") 
    public <T extends Enum<T> & Bar> String getMe(Z z, String fooValue) { 
     Class<T> fooEnum = (Class<T>) z.getMyEnum(); 
     return Enum.valueOf(fooEnum, fooValue).getMe(); 
    } 
} 

Внешне параметр типа бесполезно. Внутри он позволяет объявить тип, который является подтипом Enum и Bar. Отливка от Bar также больше не нужна.

+0

И благодаря специальным правилам перечисления это примерно так же безопасно, как и непроверенные. – Radiodef

+0

@Radiodef Я хотел бы услышать, в каком смысле и почему. Нет типа 'Enum', где два'? 'Появляются в объявлении' Class > 'будет отличаться. Enum не являются общей концепцией. Здесь нет никаких бросков, о которых я могу думать (дайте какие-либо входы), которые могут привести к сбою. –

+0

Вот что я имею в виду. Бросок никогда не должен терпеть неудачу. – Radiodef

0

В принципе невозможно выразить отношение типа, которое вам нужно, учитывая настоящие общие грамматические конструкции Java. Таким образом, вы можете сделать что-то непроверенное, или, если все, что вам нужно сделать что-то вроде

String str = someX.getMe(Z1, "VALUE1"); 

, то вы можете угробить перечисление и объявить Z как обычный класс, который принимает параметр. Таким образом, вы сохраняете полный аргумент типа и можете использовать его позже.

public final class Z<E extends Enum<E> & Bar> { 
    public static final Z<Foo1> Z1 = new Z<>(Foo1.class); 
    public static final Z<Foo2> Z2 = new Z<>(Foo2.class); 

    private final Class<E> myEnumClass; 

    private Z(Class<E> myEnumClass) { 
     this.myEnumClass = myEnumClass; 
    } 

    public Class<E> getMyEnumClass() { 
     return myEnumClass; 
    } 

    /* 
    * recreate enum functionality if needed 
    */ 
} 

public <E extends Enum<E> & Bar> String getMe(Z<E> z, String fooValue) { 
    Class<E> fooEnumClass = z.getMyEnumClass(); 
    return Enum.valueOf(fooEnumClass, fooValue).getMe(); 
} 

Enum не очень гибкий. Есть вещи, которые он просто не может сделать, и это может быть неприемлемо.