Answers:
错误消息说明了一切。在运行时,该类型已消失,无法对其进行检查。
您可以通过为对象创建工厂来捕获它,如下所示:
public static <T> MyObject<T> createMyObject(Class<T> type) {
return new MyObject<T>(type);
}
然后在对象的构造函数中存储该类型,变量,以便您的方法如下所示:
if (arg0 != null && !(this.type.isAssignableFrom(arg0.getClass()))
{
return -1;
}
使用泛型进行运行时类型检查的两个选项:
选项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(您的通用类型),只是为了欺骗编译器。您的类型转换在运行时不执行任何操作,但是当您尝试将错误类型的对象传递给抽象方法时,仍然会收到ClassCastException。
注意1:如果您在抽象方法中执行其他未经检查的强制转换,则ClassCastExceptions将在此处被捕获。那可能是好事也可能是坏事,因此请仔细考虑。
注意2:使用instanceof时,您将获得免费的空检查。由于您无法使用它,因此您可能需要赤手检查null。
旧帖子,但是做普通instanceOf检查的一种简单方法。
public static <T> boolean isInstanceOf(Class<T> clazz, Class<T> targetClass) {
return clazz.isInstance(targetClass);
}
如果您的类扩展了具有通用参数的类,则您还可以在运行时通过反射来获取它,然后将其用于比较,即
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()方法通过索引获取其他参数化类型。
我遇到了同样的问题,这是我的解决方案(非常谦虚,@ george:这一次编译并正在工作……)。
我的探针位于实现Observer的抽象类中。Observable可以使用Object类触发update(...)方法,该类可以是任何种类的Object。
我只想处理T类型的对象
解决方案是将类传递给构造函数,以便能够在运行时比较类型。
public abstract class AbstractOne<T> implements Observer {
private Class<T> tClass;
public AbstractOne(Class<T> clazz) {
tClass = clazz;
}
@Override
public void update(Observable o, Object arg) {
if (tClass.isInstance(arg)) {
// Here I am, arg has the type T
foo((T) arg);
}
}
public abstract foo(T t);
}
对于实现,我们只需要将Class传递给构造函数
public class OneImpl extends AbstractOne<Rule> {
public OneImpl() {
super(Rule.class);
}
@Override
public void foo(Rule t){
}
}
否则您可能会尝试将E转换为E失败。
public int indexOf(Object arg0){
try{
E test=(E)arg0;
return doStuff(test);
}catch(ClassCastException e){
return -1;
}
}
从技术上讲,您不必这样做,这就是泛型的重点,因此您可以进行编译类型检查:
public int indexOf(E arg0) {
...
}
但是如果您有一个类层次结构,那么@Override可能是一个问题。否则,请参见Yishai的答案。
对象的运行时类型是要过滤的相对任意的条件。我建议远离您的收藏夹。这可以简单地通过将您的集合委托给构造中传递的过滤器来实现。
public interface FilterObject {
boolean isAllowed(Object obj);
}
public class FilterOptimizedList<E> implements List<E> {
private final FilterObject filter;
...
public FilterOptimizedList(FilterObject filter) {
if (filter == null) {
throw NullPointerException();
}
this.filter = filter;
}
...
public int indexOf(Object obj) {
if (!filter.isAllows(obj)) {
return -1;
}
...
}
...
}
final List<String> longStrs = new FilterOptimizedList<String>(
new FilterObject() { public boolean isAllowed(Object obj) {
if (obj == null) {
return true;
} else if (obj instanceof String) {
String str = (String)str;
return str.length() > = 4;
} else {
return false;
}
}}
);
Comparator
或类似的方法来检查实例类型。)
Class.isAssignableFrom
。