Issue
Here is how I managed to constructor objects at runtime based on the subclass I want to invoke (to avoid having to update a Factory class every time I want to add a new subclass):
import java.lang.reflect.InvocationTargetException;
public class Main{
private static final class X{}
private static abstract class A{
public A(X x){}
public static A newInstance(Class<? extends A> subType, X x) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
return subType.getConstructor(X.class).newInstance(x);
}
}
private static final class A_1 extends A{
public A_1(X x){
super(x);
//...
}
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
for(int i = 0; i < 1000; i++){
X x = new X();
long t = System.currentTimeMillis();
A a = A.newInstance(A_1.class, x);
t = System.currentTimeMillis() - t;
System.out.println(t);
}
}
}
At first I thought it would be slow but I'm getting 1ms for the first iteration and 0 for any consecutive instantiation.
Can I expect a similar behavior once my application is deployed (Here I simplified the process but it's hardly any harder in the context of my application).
What are the pros and cons of doing such a technique?
Solution
Reflection is almost always the worst way to do things.
- Reflection is slow. It usually cannot be optimized at runtime by the just-in-time compiler.
- Reflection is bug prone. The compiler cannot verify correctness of reflection code. In your case, the compiler can’t guarantee that
subType
has a constructor which takes a single X argument. - Reflection is hard to follow in code and thus hard to maintain.
In your case, you want a Function that represents the subclass constructor:
public static A newInstance(Function<? super X, ? extends A> constructor, X x) {
return constructor.apply(x);
}
You would call that method with a method reference:
A a = newInstance(A_1::new, x);
Answered By - VGR