Why makes a class class to class <T> unsafe?
I am creating a MethodPointer class to simulate the functionality of function pointers from C ++. At first I did everything with Object s, but then I had the thought - why not make it really generic?
The problem arose in this constructor, which tried to call another constructor with the signature MethodPointer(Class<T> clazz, String methodName, Class<?> ... paramClasses) :
public MethodPointer(T object, String methodName, Class<?> ... paramClasses) { this(object.getClass(), methodName, paramClasses); this.object = object; } I assumed that this would work fine, but I got the following compiler error:
The constructor MethodPointer<T>(Class<capture#1-of ? extends Object>, String, Class<?>[]) is undefined So embarrassed, I did this:
public MethodPointer(T object, String methodName, Class<?> ... paramClasses) { this((Class<T>) object.getClass(), methodName, paramClasses); this.object = object; } Now it compiles, but I get the following warning:
Unchecked cast from Class<capture#1-of ? extends Object> to Class<T> I think the problem is that I do not understand what Class<capture#1-of ? extends Object> means Class<capture#1-of ? extends Object> Class<capture#1-of ? extends Object> . I thought that since the type T is derived from the parameter T object , it would be necessary for the call to object.getClass() return a Class object of type Class<T> . This is apparently not the case. Can someone clear my confusion?
Full class declaration and all constructors:
public class MethodPointer<T> { //Logger instance private static final Logger LOGGER = Logger.getLogger(MethodPointer.class); //Object fields private final Method method; private ArrayList<Object> args = new ArrayList<Object>(); private T object = null; //Constructors public MethodPointer(Method method) { this.method = method; } public MethodPointer(Class<T> clazz, String methodName, Class<?> ... paramClasses) { Method theMethod = null; try { theMethod = clazz.getMethod(methodName, paramClasses); } catch(NoSuchMethodException nsme) { LogUtil.log(LOGGER, Level.ERROR, "Unable to find method " + methodName + " in " + clazz.getSimpleName(), nsme); } method = theMethod; } public MethodPointer(T object, String methodName, Class<?> ... paramClasses) { this((Class<T>) object.getClass(), methodName, paramClasses); this.object = object; } SLaks answer indicates that object.getClass() splits into Class<? extends Object> Class<? extends Object> to explain a compilation error. But it is unsafe to send to Class<T> .
getClass "returns the runtime class" of the object it called on. For example, if we are inside MethodPointer<Number> , then object is-a Number , but its execution type can be Integer , Double , etc. This tells us that casting object.getClass() in Class<T> unsafe because Class<Integer> and Class<Number> are different objects representing different classes - this is a distinction that seems very relevant for the correctness of what you trying to do.
So what is the solution? Well, don't quit. Insist on accepting Class<T> from the caller.
The problem is that getClass() ignores type parameters.
Javadocs say:
Actual result type
Class<? extends |X|>Class<? extends |X|>where|X|- This erases the static type of the expression on which getClass is called.
For example, new ArrayList<String>().getClass() returns Class<? extends ArrayList> Class<? extends ArrayList> , not Class<? extends ArrayList<String>> Class<? extends ArrayList<String>> .
This also means that getClass() , called by the type parameter, splits into Class<? extends Object> Class<? extends Object> .
If you do not need the specified class type, you can use
Class<?> for parameters.
So you have an unrelated type for your classes.
And if you want to get an instance, you can use it as follows:
obj.getClass().getDeclaredConstructor(Class<?> parameterTypes)