As mentioned, type erasure of generic types does not allow that. But you can achieve what you want like this:
public class BaseClass {
public BaseClass(int theParam) {
// ...whatever...
}
public BaseClass() {
}
}
public class DerivedType extends BaseClass {
}
And now doIt() method gets the class argument for reference:
public <D extends BaseClass> boolean doIt (ArrayList<D> target, Class<D> c)
{
try {
D newElem = c.getDeclaredConstructor(int.class).newInstance(5);
} catch (Exception e) {}
// ...other code does not matter...
return true ;
}
And you should call it like this:
ArrayList<DerivedType> testList = new ArrayList<DerivedType>();
testList.add(new DerivedType());
testList.add(new DerivedType());
doIt(testList, DerivedType.class);
Hope that helps :)
Note that, one may really want to be hacky and get rid of the class parameter and try this:
public static <D extends BaseClass> boolean doIt (ArrayList<D> target)
{
try {
D newElem1 = ((Class<D>) ((ParameterizedType) target.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).getDeclaredConstructor(int.class).newInstance(5);
} catch (Exception e) { e.printStackTrace();}
return true ;
}
}
In fact I thought so before the second edit :) But this gets a "java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class" exception as you mention (I didn't see it because of an overlooked catch statement). In short, Java runtime system does not store the parameterized types (in favor of backwards compatibility; so this may change in the future).
So, it looks like it is not possible without 'touching' some class.
However, other than the mentioned methods, I can think of two more things. First, if both the BaseClass and the DerivedType 'D' class implement clone() method, you can get a clone of an object from the array and then use it:
D o = target.get(0);
D oNew = (D)((BaseClass)o).clone();
target.add(oNew);
Polymorphism will take care of the rest :)
The second one is not a real 'solution', but can be used if all you want is a new instance for an array of objects parameterized by type. Type Erasure only happens for parameterized types, but it does not happen for basic arrays (arrays are reified in JVM). So if we have the freedom to change the signature of the method and working with arrays is ok, then the following would work:
public <D extends BaseClass> boolean doIt(D[] target) {
try {
D newD = (D) (target.getClass().getComponentType().getConstructor(int.class).newInstance(8));
target[0] = newD;
// The following is optional, if we want to work with Collections internally
List<D> l = new ArrayList<D>(Arrays.asList(target));
l.add(newD);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
Note: Super type tokens would not work for this problem if we cannot introduce new parameters. Please correct me if I'm wrong.