为什么要将泛型的类转换为类< T>不安全? [英] Why is casting the class of a generic to Class<T> unsafe?
问题描述
我创建一个 MethodPointer
类,以模拟来自C ++的函数指针的功能。起初,我只是用 Object
做所有的事,但后来我有了一个想法 - 为什么不把它做成通用的?
问题出现在这个构造函数中,它试图用签名 MethodPointer(Class< T> clazz,String methodName,Class<?> ... paramClasses) code>:
public MethodPointer(T object,String methodName,Class<?> ... paramClasses){
this(object.getClass(),methodName,paramClasses);
this.object = object;
}
我假设这将正常工作,但我收到以下编译器错误:
构造函数MethodPointer< T>(Class< capture#1-of?extends Object>,
String, ;>> [])未定义
public MethodPointer(T object,String methodName,Class<?> ... paramClasses){
this((Class< T> ;)object.getClass(),methodName,paramClasses);
this.object = object;
}
现在已编译,但收到以下警告:
从< capture#1-of类取消选中的投射extends Object>到类< T>
我想问题是我不明白 Class< capture #1 - 的? extends Object>
表示。我认为由于 T
的类型是从 T对象
参数中推断出的, / em> object.getClass()
返回类
的类 T>
。显然不是这样的情况。
public class MethodPointer< T> {
//记录器实例
private static final Logger LOGGER = Logger.getLogger(MethodPointer.class);
//对象字段
private final方法方法;
private ArrayList< Object> args = new ArrayList< Object>();
private T object = null;
//构造方法
public MethodPointer(方法方法){
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,无法在+ clazz.getSimpleName(),nsme中找到方法+ methodName + ;
}
method = theMethod;
}
public MethodPointer(T object,String methodName,Class<?> ... paramClasses){
this((Class< T>)object.getClass ,methodName,paramClasses);
this.object = object;
}
SLaks的回答指出 object.getClass()
衰减到类< ;? extends Object>
,以解释编译错误。但是不安全可以投射到类< T>
。
getClass
返回它所调用的对象的运行时类。例如,如果我们在 MethodPointer< Number>
中,则 object
is-a Number
,但其运行时类型可以是 Integer
, Double
等。这告诉我们,将 object.getClass()
转换为类< T>
Class< Integer>
和 Class< Number>
是不同的对象,代表不同的类 -
这是什么解决方案?好吧,不要投。坚持从呼叫者接受课堂< T>
。
I'm making a MethodPointer
class in order to simulate the functionality of function pointers from C++. At first, I was doing everything with just Object
s, but then I had a thought -- why not make it truly generic?
The problem came in this constructor, which attempted 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 this would work just fine, but I received the following compiler error:
The constructor MethodPointer<T>(Class<capture#1-of ? extends Object>,
String, Class<?>[]) is undefined
So, confused, I did this:
public MethodPointer(T object, String methodName, Class<?> ... paramClasses) {
this((Class<T>) object.getClass(), methodName, paramClasses);
this.object = object;
}
It now compiles, but I receive the following warning:
Unchecked cast from Class<capture#1-of ? extends Object> to Class<T>
I guess the problem is that I don't understand what Class<capture#1-of ? extends Object>
means. I thought that since the type of T
is inferred from the T object
parameter that it would be necessary that calling object.getClass()
returns a Class
object of type Class<T>
. Apparently this isn't the case, though. Can someone clear up 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 points out that object.getClass()
decays to Class<? extends Object>
, to explain the compile error. But it's not safe to cast to Class<T>
.
getClass
"returns the runtime class" of the object it's called on. For example, if we're inside a MethodPointer<Number>
, then object
is-a Number
but its runtime type could be Integer
, Double
, etc. That tells us that casting object.getClass()
to Class<T>
isn't safe because Class<Integer>
and Class<Number>
are different objects, representing different classes - a distinction that seems very relevant to the correctness of what you're trying to do.
So what's the solution? Well, don't cast. Insist on taking a Class<T>
from the caller.
这篇关于为什么要将泛型的类转换为类< T>不安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!