Java: создать вектор из N экземпляров подклассов - PullRequest
0 голосов
/ 07 февраля 2019

Я хочу иметь возможность получить список / ArrayList из N новых экземпляров статического метода, унаследованного подклассами, чтобы мне не приходилось переписывать эту одну и ту же функцию во всех подклассах.

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

public class Parent {

   public static List<Parent> getNInstances(int n) {
       List<Parent> out = new ArrayList<>();
       for (int i = 0; i < n; i++) {
          Parent newChildInstance = (Parent) MethodHandles
                                               .lookup()
                                               .lookupClass()
                                               .getConstructor()
                                               .newInstance()
          out.add(newChildInstance);
      }
   } 
}

У меня естьполучил метод MethodHandles от здесь , так как я чувствую, что мне нужно, чтобы класс мог вызывать .getConstructor().newInstance(), что, теоретически, должно решить мою проблему.Тем не менее, это не работает, это дает мне NoSuchMethodException, так как он не может найти конструктор из класса, заданного MethodHandles.lookup().lookupClass(), по крайней мере, я думаю, именно поэтому.

Вот как я хотел быметод .getNInstances() для работы.

public class Parent {

   public Parent(){  }

   public static List<Parent> getNInstances(int n) {
   List<Parent> out = new ArrayList<>();
   for (int i = 0; i < n; i++) {
      Parent newChildInstance = ...
      out.add(newChildInstance);
      }
   } 
}
public class A extends Parent {
   public A(){ }
}
public class B extends Parent {
   public B(){ }
}
public class Main {
   public static void main(String[] args) {
       List<Parent> total = new ArrayList<>();

       total.addAll(A.getNInstances(3));
       total.addAll(B.getNInstances(4));
   }
}

Здесь итоговое значение должно быть таким, как [a, a, a, b, b, b, b], где a являетсяэкземпляр A и b экземпляр B, но сейчас он просто пуст.

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Мне не удалось воспроизвести вашу ошибку.Но обратите внимание на некоторые моменты:

1) Здесь вы никогда не будете искать класс подклассов, потому что lookupClass() возвращает класс, который вызвал метод, и это всегда Parent.getNInstances():

Parent newChildInstance = (Parent) MethodHandles
        .lookup()
        .lookupClass()
        .getConstructor()
        .newInstance();

Сделайте так, чтобы метод экземпляра давал тот же результат.

2) Универсального класса должно быть достаточно, чтобы решить вашу проблему и сделать его методом экземпляра.

public class Parent<T extends Parent> {

    public List<Parent> getNInstances(int n) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        List<Parent> out = new ArrayList<>();
        for (int i = 0; i < n; i++) {

            Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
                    .getGenericSuperclass()).getActualTypeArguments()[0];
            Parent newChildInstance =
                    clazz.getConstructor().newInstance();

            out.add(newChildInstance);
        }
        return out;
    }

}

И подклассы:

public class A extends Parent<A> {
    //...
}

public class B extends Parent<B> {
    //...
}

Образец теста:

List<Parent> total = new ArrayList<>();    
total.addAll(new A().getNInstances(3));
total.addAll(new B().getNInstances(4));

System.out.println(total);

Выходы:

[A @ 506e6d5e, A@ 96532d6, A @ 3796751b, B @ 67b64c45, B @ 4411d970, B @ 6442b0a6, B @ 60f82f98]

0 голосов
/ 07 февраля 2019

Нет необходимости использовать отражение здесь.Используйте фабрику и ссылку на метод для конструктора.

Таким образом, вы получаете уверенность во время компиляции, что конструктор, который вы пытаетесь использовать, действительно существует.

abstract class ParentFactory
{
    public List<Parent> getNInstances(int n)
    {
        final List<Parent> out = new ArrayList<>();
        for (int i = 0; i < n; i++)
        {
            out.add(constructor().get());
        }
        return out;
    }

    protected abstract Supplier<Parent> constructor();
}

class AFactory extends ParentFactory
{
    @Override
    protected Supplier<Parent> constructor() {
        return A::new;
    }
}

class BFactory extends ParentFactory
{
    @Override
    protected Supplier<Parent> constructor() {
        return B::new;
    }
}

Пример использования:

List<Parent> total = new ArrayList<>();

total.addAll(new AFactory().getNInstances(3));
total.addAll(new BFactory().getNInstances(4));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...