Java:创建N个子类实例的向量

时间:2019-02-07 15:52:35

标签: java inheritance methods instance

我希望能够从继承到子类的静态方法中获取N个新实例的List / ArrayList,这样我就不必在所有子类中都重写同一函数。

我想实现这一点,以便构建包含A和B的向量。我尝试了几种方法,但没有一种对我有用:

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);
      }
   } 
}

我从here获得了MethodHandles的东西,因为我觉得我需要让该类能够调用.getConstructor().newInstance(),这在理论上应该可以解决我的问题。但是,这是行不通的,它给了我一个NoSuchMethodException,因为他不能从给定的Class中找到构造函数。 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 :(得分:2)

这里根本不需要使用反射。为构造函数使用工厂和方法引用。

这样,您可以在编译时确保要使用的构造函数确实存在。

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));

答案 1 :(得分:0)

我无法重现您的错误。 但请注意以下几点:

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]