instanceof java list_Java:Instanceof和泛型

在查看通用数据结构中的值索引之前,我想看看它是否甚至已被参数化为类型this的实例。

但是当我这样做时,Eclipse会抱怨:

@Override

public int indexOf(Object arg0) {

if (!(arg0 instanceof E)) {

return -1;

}

这是错误消息:

Cannot perform instanceof check against type parameter E. Use instead its erasure Object since generic type information will be erased at runtime

有什么更好的方法呢?

错误消息说明了一切。在运行时,该类型已消失,无法对其进行检查。

您可以通过为对象创建工厂来捕获它,如下所示:

public static < T > MyObject< T > createMyObject(Class< T > type) {

return new MyObject< T >(type);

}

然后在对象的构造函数中存储该类型,变量,以便您的方法如下所示:

if (arg0 != null && !(this.type.isAssignableFrom(arg0.getClass()))

{

return -1;

}

我不认为您想要Class.isAssignableFrom。

@Tom,我昨晚是从记忆中写这本书的,我将其固定为实际上通过了课程(duh!),但否则,我不明白您为什么不想要它(也许今天早上我需要更多咖啡,我只在我的第一杯咖啡上)。

我和汤姆在一起。你能澄清一下吗?使用isAssignableFrom()将是我的工作选择。也许我错过了什么?

@ luis,Toms评论可能意味着我应该使用isInstance()并传递实际的arg0参数。它具有避免空检查的优点。

我有类似的情况,但我无法完全理解答案。你能为像我这样的假人澄清一下吗?

@RubensMariuzzo可能有帮助:ralfebert.de/blog/java/isassignablefrom的重要部分是:isAssignableFrom告诉您泛型T是否是实例arg0的超类。

@ Emerald214,您不需要扩展该类,但是该类具有静态方法(这是静态工厂模式javaworld.com/javaworld/jw-06-2001/j1-01-sintes2.html)

使用泛型进行运行时类型检查的两个选项:

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

{

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 {

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;

}

}

+1实用的非工程化解决方案,可轻松进行检查!我希望我能投票更多

这不会工作。 E在运行时被擦除,因此强制类型转换不会失败,您只会收到编译器警告。

对象的运行时类型是要过滤的相对任意的条件。我建议远离您的收藏夹。只需将您的集合委托给构造中传递的过滤器即可实现。

public interface FilterObject {

boolean isAllowed(Object obj);

}

public class FilterOptimizedList implements List {

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 longStrs = new FilterOptimizedList(

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或类似版本,则可能要检查实例类型。)

从技术上讲,您不必这样做,这就是泛型的重点,因此您可以进行编译类型检查:

public int indexOf(E arg0) {

...

}

但是如果您有一个类层次结构,那么@Override可能是一个问题。否则,请参见Yishai的答案。

是的,List接口要求该函数采用对象参数。

您实施清单?为什么不实施List ?

(例如,参见ArrayList的声明:java.sun.com/j2se/1.5.0/docs/api/java/util/ArrayList.html)

@Rosarch:List接口的indexOf()方法不需要给定的参数与您要查找的对象具有相同的类型。它只是必须等于.equals(),并且不同类型的对象可以彼此等于.equals()。这与remove()方法的问题相同,请参见:stackoverflow.com/questions/104799/

[[[sheepishly]]]没关系,我认为indexOf()要求E作为参数而不是Object。 (他们为什么这样做?!?!)

@Jason基本上是因为它会破坏不需要有效类型转换的完全有效的代码。另外,由于泛型不是协变的,因此即使使用indexOf()实际上返回一个实数索引(对象),您也会陷入一些带有类型参数的极端情况(例如,列表本身具有类型参数的列表)在列表中,但编译器无法让您看到它)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值