This is my code: The ExecutorImp extends AbstractExecutor which extract the same execute logics of its implementers(ExecutorImp is one case),when calling the execute() method of ExecutorImp, it will call the method in its supertype,but the supertype (the AbstractExcutor) should know another class binding to the implementer(in the example, it is the User class):
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
abstract class AbstractExecutor<E> {
public void execute() throws Exception {
ArrayList<E> list = new ArrayList<E>();
// here I want to get the real type of 'E'
Class cl = this.getClass().getTypeParameters()[0].getGenericDeclaration().getClass();
Object o = cl.getConstructor(String.class).newInstance("Gate");
list.add((E) o);
System.out.println(format(list));
}
public abstract String format(ArrayList<E> list);
public abstract String getType();
}
public class ExectorImp<E> extends AbstractExecutor<User> {
@Override
public String getType() {
return "user";
}
@Override
public String format(ArrayList<User> list) {
StringBuffer sb = new StringBuffer();
for (User u : list) {
sb.append(u.toString() + " ");
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
new ExectorImp().execute();
}
}
class User {
String name;
public User(String name) {
this.name = name;
}
}
SO, what is the problem with my codes?
Usual approach to fix the problem is to slightly change the code. Define constructor on the base class accepting
Class<E>
parameter. Assign this parameter to internal field.On the subclass define constructor without parameters and call
super(User.class)
from there.This way you will know class of argument without much overburden for clients of subclasses.
There's some confusion here. Due to type erasure you can't get type information from the runtime parameterized type like:
However, you can obtain compiletime parameterized type information from class, field and method declaration by
ParameterizedType#getActualTypeArguments()
.Update: as to whether this is recommended or not, although this will work, this is sensitive to runtime problems whenever minor changes in the class declaration occur. You as developer should document it properly. As a completely different alternative, you can make use of polymorphism.
and implement
UserExecutor
accordingly.I think you should use
getActualTypeParameters
; asgetTypeParameters
does not refer to what has been put in your current instantiation in place ofE
, but toE
itself (to describe how is it bounded, etc.).In order to get the
ParameterizedType
you should usegetGenericSuperclass
first.update: but the above only works if the current object is derived from a generic class with the generic argument instantiated, like:
should return
String.class
.I don't think you could get the generic type at runtime. The generic type is a restriction that applies at compile time. As I remember at runtime there is no difference between a generic collection and a collection without a generic type.