考虑两辆车,一辆汽车和一辆火车。 Car的构造函数接收两个参数,Train的构造函数接收一个参数。参数在类型和数量上都不同。我想要一个可以在Java中使用varargs调用两个构造函数的泛型方法。假设我不能改变车辆,汽车和火车。
问题在于如何在方法args
中展开doSomething
。在args
类型的新实例中抛出变量M
将不起作用。这可行吗?
public class MainTest {
// Receive concrete type of vehicle and arguments for its constructor (variable)
public <M extends Vehicle> M doSomething(Class<M> a, Object... args)
throws InstantiationException, IllegalAccessException {
// How to pass variable number of arguments for the constructors?
M m = a.newInstance( args ); // <-- Problem is here, possible to solve?
return m;
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
MainTest test = new MainTest();
Car c = test.doSomething(Car.class, "Jill", 35);
Train t = test.doSomething(Train.class, 35.1);
}
}
public class Vehicle {
/* currently empty */
}
public class Car extends Vehicle {
public Car(String name, int n) {
}
}
public class Train extends Vehicle {
public Train(double d) {
}
}
答案 0 :(得分:3)
问题是the newInstance
method没有任何参数。它调用无参数构造函数(如果存在)。
要在只有类时将参数传递给构造函数,您需要使用反射来查找适当的构造函数。在Class
对象上,调用the getConstructors()
method并遍历返回的Constructor
个对象数组以查找相应的对象,或调用the getConstructor
method,传递Class
个对象表示获取特定构造函数的参数类型。由于您列出的每个类只有一个构造函数,因此只需获取getConstructors()
返回的数组的第一个元素。
当你拥有适当的Constructor
时,调用它的newInstance
method,它确实在其参数中包含构造函数参数。
答案 1 :(得分:1)
原油示例......
public <M extends Vehicle> M doSomething(Class<M> a, Object... args)
throws Exception {
for(Constructor constructor : a.getConstructors()) {
if(constructor.getParameterTypes().length == args.length) {
return (M) constructor.newInstance(args);
}
}
throw new Exception("constructor not found");
}
答案 2 :(得分:1)
使用工厂设计模式可以更优雅地解决您的问题。
创建一个枚举:
enum VehicleType {CAR, TRAIN;}
然后您的工厂方法变为:
@SuppressWarnings("unchecked")
public static <T extends Vehicle> T buildVehicle(VehicleType model, Object... args) {
switch (model) {
case CAR:
return (T) new Car((String) args[0], (int) args[1]);
case TRAIN:
return (T) new Train((double) args[0]);
default:
throw new IllegalArgumentException();
}
}
最后主要是:
Car c = buildVehicle(VehicleType.CAR, "Jill", 35);
Train t = buildVehicle(VehicleType.TRAIN, 35.2);
不再需要反思和更好的代码IMO。