2015-12-28 3 views
0

Я хочу создать перечислитель с классами, чтобы получить эти классы в дополнительном коде, но я не могу. я объясню на примере, что я хочу сделать:Java Generic Enumerator для классов

public enum SomeEnumeratorForClasses { 
    FIRST_CLASS("Name 1", FirstClass.class), 
    SECOND_CLASS("Name 2", SecondClass.class); 

    private String name; 
    private Class<T> response; 

    SomeEnumeratorForClasses (String name, Class<T> clazz) {...} 

    public Class<T> getResponse() { 
    return response; 
    } 
} 

Например каждый класс первый/второй имеет некоторые поля/метод пример:

getDescription() 

И, наконец, в другом классе я хочу что-то вроде что:

SomeEnumeratorForClasses.FIRST_CLASS.getResponse().getDescription(); 

Но я не могу этого сделать. Каждый класс наследует от другого базового класса Zero.class например:

FirstClass extends Zero 
SecondClass extends Zero 

Я пытаюсь сделать это также вместо

private Class<T> response; 

использовать это:

private Class<? extends Zero> response; 

Но до сих пор не работает.

Метод getDescription не является статичным, является публичной строки, например:

class FirstClass { 
    public String getDescription() { 
    return "Text"; 
    } 
} 

Некоторые методы, такие как getDesciptions абстрактны в нулевой класс. Как я могу это сделать?

+0

Это не статический метод, является метод общественного типа String. – ullQuiorra

+0

Ваш 'getDescription' объявлен в классе« Zero »? Это только метод, к которому вы хотите получить доступ через это перечисление? – Pshemo

+1

Если он не является статическим, то для его вызова вам нужен * экземпляр *, на который он будет вызываться (подобно тому, как getter нуждается в экземпляре, из которого он будет считывать значение, которое ему нужно вернуть), а не литералу класса. – Pshemo

ответ

0

Если вы знаете, что каждый класс разделяет подпись конструктора (предпочтительно общедоступную версию без аргументов), вы можете написать функцию, которая их создает.

public class ObjectUtils { 
    private ObjectUtils(){} 

    public static <T> T init(Class<T> clazz, Object... args) { 
     try { 

      return (T) Arrays.stream(clazz.getConstructors()) 
        .filter(construct -> Objects.equals(args.length, construct.getParameterCount())) 
        .filter(construct -> IntStream.range(0, construct.getParameterTypes().length) 
          .allMatch(val -> construct.getParameterTypes()[val].isAssignableFrom(args[val].getClass()))) 
        .findFirst().orElseThrow(() -> new InstantiationException("Could not find compatible constructor.")) 
        .newInstance(args); 

     } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) { 
      throw new RuntimeException("Could not instantiate class for provided arguments.", e); 
     } 
    } 
} 

Теперь, ваше перечисление может выглядеть следующим образом:

public enum SomeEnumeratorForClasses { 
    FIRST_CLASS("Name 1", FirstClass.class), 
    SECOND_CLASS("Name 2", SecondClass.class); 

    private String name; 
    private Class<? extends Zero> responseClass; 

    SomeEnumeratorForClasses (String name, Class<? extends Zero> responseClass) { 
     this.name = name; 
     this.responseClass = responseClass; 
    } 

    public <T extends Zero> T getResponse() { 
    return ObjectUtils.init(responseClass); 
    } 
} 

И использовать его так:

SomeEnumeratorForClasses.FIRST_CLASS.getResponse().getDescription(); 
Смежные вопросы