Java Generics инициализация дочернего класса в базовом классе - PullRequest
0 голосов
/ 03 ноября 2018

Я довольно новичок в Java и не особенно уверен, как инициализировать универсальный тип / дочерний класс из базового класса.
По сути, у меня есть несколько классов, расширяющих абстрактный класс BaseClass, которые необходимо инициализировать и добавить в карту instance, если ключ отсутствует.
Дочерний класс используется повторно несколько раз, но динамически создается на основе параметра key.

Я бы хотел избежать размышлений и не против поменять шаблон, если это не «путь Java».
Что у меня сейчас есть:

public abstract class BaseClass<T> {
    protected Map<String, T> instance = new HashMap<String, T>();

    public T Get(String key) {
        if (this.instance.containsKey(key)) {
            return this.instance.get(key);
        } 
        T item = new T(key); // Obviously this line errors but you get the idea
        instance.put(key, item);
        return item;
    }
}

// Example top class which extends my base class
public class TopClass extends BaseClass<TopClass> {
    public TopClass(String key) {
        // Do unique initialization stuff
    }
}

Ответы [ 3 ]

0 голосов
/ 03 ноября 2018

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

Использование String в качестве ключей для графа вашего объекта намного более подвержено ошибкам. Поэтому вы можете рассмотреть возможность использования токенов типа. Проверьте эту исправленную версию.

public class BaseClass {
    protected Map<Class<?>, Object> instance = new HashMap<>();

    @SuppressWarnings("unchecked")
    public <T> T Get(Class<?> key) {
        return (T) instance.computeIfAbsent(key, this::newInstance);
    }

    private Object newInstance(Class<?> type) {
        try {
            Constructor<?>[] constructors = type.getConstructors();
            Object[] args = null; // setup your constructor args here.
            return constructors[0].newInstance(args);
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
}

С другой стороны, создание общего класса выглядит немного неловко в этом контексте. Вместо этого вы можете создать универсальный метод и использовать его для хранения любого экземпляра в соответствии с его типом в таблице.

0 голосов
/ 03 ноября 2018

У меня есть другой подход к этому.

Есть интерфейс MyInterface.

   public interface MyIinterface{
      public void doSomething();
   }

Создайте множество реализаций этого интерфейса.

@Component
public class MyImplementation1 implements MyInterface{

    @Override
    public void doSomething(){

    }
}

Используйте пружинные стержни в зависимости.

Аннотируйте все реализации с помощью @ Component.

@Component
public class MyImplementation1 implements MyInterface{
.
.

В некотором классе Util есть метод, который даст вам реализацию на основе строкового ключа.

public static MyInterface getImplementation(String name){

  ApplicationContext context;
  return context.getBeanByName(name);

}
0 голосов
/ 03 ноября 2018

Поскольку универсальные типы стираются во время выполнения, вы не можете этого сделать. Вместо этого вы можете использовать переменную Class следующим образом:

public T Get(Class<T> clazz, String key) throws Exception {
    if (this.instance.containsKey(key)) {
        return this.instance.get(key);
    } 
    T item = clazz.getDeclaredConstructor(String.class).newInstance(key);
    instance.put(key, item);
    return item;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...