开发者

How to avoid unchecked casts in overriden Collection's methods?

I'm working on a List implementation. Because of this, I'll have to override the methods

Collection.containsAll(Collection<?> c);
Collection.removeAll(Collection<?> c);
Collection.retainAll(Collection<?> c);

But as it's explained by Sun, they accept collections with any kind of content (note the <?>). So the collection is not checked by the compiler and it's up to me, to check it. But how to do it? instanceof on e开发者_开发技巧ach element won't work because of type erasure. The next solution would be to cast each element an catch the ClassCastException. Look here:

public boolean containsAll( Collection<?> c ) {
    boolean foundAll = true;
    for ( Object element : c ) {
        try {
            foundAll &= this.contains( (T) element );
        } catch ( ClassCastException e ) {
            foundAll = false;
        }
    }
    return foundAll;
}

The other two methods look similar. That works. But it gives me compiler warning "warning: [unchecked] unchecked cast"! Unless I suppress it with "@SuppressWarnings("unchecked")", it won't compile fine.

I don't want to rely on "@SuppressWarnings("unchecked")" unless I really have to. Is there a way to avoid it? How would you implement those methods like containsAll(Collection<?> c)?

edit

Ok, sorry guys, I was not clear enough. I don't extend AbstractList, and I don't want to. My list is implemented by a balanced binary tree. I have an own implementation of insert(), remove(), contains() (that actually does a search for the leaf), etc, and all take an argument of (generic) type T. The key goal is to have a sorted list that can be modified while it's iterated through.

So... how do I avoid the warning in containsAll(Collection <?>)? I have to cast!

Thanks! craesh


You don't need to cast your element to T when you call contains() since it is defined as boolean contains(Object o). Note that you can ask a Collection<String> if it contains() an Integer object. There's no casting necessary.

remove() takes an Object as well, so no casting should be necessary at all.

And by the way: extending AbstractList takes away most of the boring work of implementing a List.


Just to clear up a misconception on generics:

instanceof on each element won't work because of type erasure.

No, that is not correct. instanceof will work just fine. "Type erasure" just means that you cannot get at the compile time type that was declared via generics for the collection you are getting - but you don't care about that anyway.

What you want to check is the run time type of the element you are getting. This is done via instanceof, is completely independent of generics, and will work.

Of course, as Joachim Sauer points out, you don't even need to check the type in this specific case, so the point is moot anyway...

Edit:

As a matter of fact, Java's AbstractCollection does it just like that:

public boolean containsAll(Collection<?> c) {
    Iterator<?> e = c.iterator();
    while (e.hasNext())
    if(!contains(e.next()))
        return false;
    return true;
}

(from the Sun JDK sources).

So you should really try to inherit from AbstractList or at least AbstractCollections


of course you can extends AbstractList in order to get these methods for free but you can also iterate this, instead of c:

@Override
public boolean containsAll(Collection<?> c) {
    Iterator<T> it = this.iterator();

    while (it.hasNext()) {
        if (!c.contains(it.next())) {
            return false;
        }
    }

    return true;
}

or simply:

@Override
public boolean containsAll(Collection<?> c) {
    for (Object o : this) {
        if (!c.contains(o)) {
            return false;
        }
    }

    return true;
}


If you don't want to extend AbstractList, at least extend AbstractCollection. Then you don't have to implement this method at all and the question is moot.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜