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; } 
+5
java generics casting type-inference
source share
3 answers

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.

+6
source share

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> .

+4
source share

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) 
0
source share

All Articles