问题
在我查看值的索引的通用数据结构之前,我想看看它是否是一个类型为this
的实例已被参数化。
但是当我这样做时Eclipse会抱怨:
@Override
public int indexOf(Object arg0) {
if (!(arg0 instanceof E)) {
return -1;
}
这是错误消息:
无法对类型参数E执行instanceof检查。请改为使用其擦除对象,因为泛型类型信息将在运行时被擦除
有什么更好的方法呢?
#1 热门回答(69 赞)
错误消息说明了一切。在运行时,类型消失了,无法检查它。
你可以通过为你的对象创建工厂来捕获它,如下所示:
public static <T> MyObject<T> createMyObject(Class<T> type) {
return new MyObject<T>(type);
}
然后在对象的构造函数存储中输入类型,这样变量使得你的方法看起来像这样:
if (arg0 != null && !(this.type.isAssignableFrom(arg0.getClass()))
{
return -1;
}
#2 热门回答(32 赞)
使用泛型进行运行时类型检查的两个选项:
选项1 - 损坏你的构造函数
假设你正在覆盖indexOf(...),并且你希望仅针对性能检查类型,以保存自己迭代整个集合。
像这样做一个肮脏的构造函数:
public MyCollection<T>(Class<T> t) {
this.t = t;
}
然后你可以使用isAssignableFrom来检查类型。
public int indexOf(Object o) {
if (
o != null &&
!t.isAssignableFrom(o.getClass())
) return -1;
//...
每次实例化对象时,都必须重复自己:
new MyCollection<Apples>(Apples.class);
你可能认为它不值得。在ArrayList.indexOf(...)的实现中,它们不检查类型是否匹配。
选项2 - 让它失败
如果你需要使用一个需要你未知类型的抽象方法,那么你真正想要的就是让编译器停止哭泣吧instanceof.如果你有这样的方法:
protected abstract void abstractMethod(T element);
你可以像这样使用它:
public int indexOf(Object o) {
try {
abstractMethod((T) o);
} catch (ClassCastException e) {
//...
你正在将对象强制转换为T(你的泛型类型),只是为了欺骗编译器.Your cast does nothing at runtime,但是当你尝试将错误类型的对象传递给抽象方法时,仍会遇到ClassCastException。
注意1:如果你在抽象方法中执行其他未经检查的强制转换,则会在此处捕获ClassCastExceptions。这可能是好事也可能是坏事,所以请仔细考虑。
注2:You get a free null check when you use instanceof。由于你无法使用它,你可能需要赤手检查空值。
#3 热门回答(12 赞)
如果你的类使用泛型参数扩展了一个类,你也可以通过反射在运行时获取它,然后使用它进行比较,即
class YourClass extends SomeOtherClass<String>
{
private Class<?> clazz;
public Class<?> getParameterizedClass()
{
if(clazz == null)
{
ParameterizedType pt = (ParameterizedType)this.getClass().getGenericSuperclass();
clazz = (Class<?>)pt.getActualTypeArguments()[0];
}
return clazz;
}
}
在上面的例子中,在运行时,你将从getParameterizedClass()获取String.class,并且它会缓存,因此你不会在多次检查时获得任何反射开销。请注意,你可以通过ParameterizedType.getActualTypeArguments()方法从索引获取其他参数化类型。