The stackoverflow question: Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic? has many correct answers that point out that you can add a Cat to List<Animal>
but not to List<Dog>
. This leads to the use of constructs like List<? extends Animal>
. I have found that there are cases where this is just not convenient and therefore I have defined classes to "down cast" the collection. (See below for an example of DownCastCollection). My question is whether you can present some cases where the best approach is to downcast? If you think it is never the best approach then can you explain why? I realize this is a bit open ended but I think the answers may be very helpful since this situation is common. I do agree that in most cases we should use the `Collection, but I am pointing out that sometimes that is just not the best approach. Have you encountered examples where this is not the best approach and if so can you present them here?
Based on the answer in https://stackoverflow.com/a/27491199/4350148 i have changed DownCastCollection to be modifiable and so now it does not return an error. The question still is valid.
Here is the downcast collection class:
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class DownCastCollection<E> extends AbstractCollection<E> implements Collection<E> {
@SuppressWarnings("rawtypes")
private Collection delegate;
public DownCastCollection(Collection<? extends E> delegate) {
if(delegate == null) throw new IllegalArgumentException();
this.delegate = delegate;
}
@Override
public int size() {
return delegate.size();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean contains(Object o) {
return delegate.contains(o);
}
private class MyIterator implements Iterator<E>{
@SuppressWarnings("rawtypes")
Iterator delegateIterator;
protected MyIterator() {
super();
this.delegateIterator = delegate.iterator();
}
@Override
public boolean hasNext() {
return delegateIterator.hasNext();
}
@SuppressWarnings("unchecked")
@Override
public E next() {
return (E)delegateIterator.next();
}
@Override
public void remove() {
delegateIterator.remove();
}
}
@Override
public Iterator<E> iterator() {
return new MyIterator();
}
@SuppressWarnings("unchecked")
@Override
public boolean add(E e) {
return delegate.add(e);
}
@Override
public boolean remove(Object o) {
return delegate.remove(o);
}
@SuppressWarnings("unchecked")
@Override
public boolean containsAll(Collection<?> c) {
return delegate.containsAll(c);
}
@SuppressWarnings("unchecked")
@Override
public boolean addAll(Collection<? extends E> c) {
return delegate.addAll(c);
}
@SuppressWarnings("unchecked")
@Override
public boolean removeAll(Collection<?> c) {
return delegate.removeAll(c);
}
@SuppressWarnings("unchecked")
@Override
public boolean retainAll(Collection<?> c) {
return delegate.retainAll(c);
}
@Override
public void clear() {
if(delegate == null) return;
delegate.clear();
}