Search code examples
javagenericscastingguavamultimap

Guava: Is it valid to cast a Multimap to generic supertypes?


Currently I'm implementing the Multimap class to allow duplicates using Multisets. In particular, I am working on the boolean putAll(Multimap<? extends K, ? extends V> multimap) method.

I want to do this:

Map<K, Collection<V>> map = ((Multimap<K, V>)multimap).asMap();

where asMap() would normally return a Map<? extends K, Collection<? extends V>>.

Is this valid (won't throw errors provided I don't add to the map)? If not, how can I fix this?


Solution

  • No, it's not valid, for the same reason that it is not valid to cast a List<T> to List<Object>.

    Multimap.asMap() returns a view, according to the documentation. This means that

    Multimap<K, V> multimap = ...;
    Map<SuperOfK, SuperOfV> map = (<some cast>) multimap.asMap();
    map.put(superOfK, superOfV);
    

    Should update the multimap. Whilst this wouldn't itself result in a ClassCastException, doing something like iterating the keys would:

    for (K key : multimap.keys()) { }
    

    Hence, it is not type safe to cast like that, so it is forbidden.

    Of course, you don't have this problem if your multimap is immutable - but it is in general the reason why you shouldn't. And saying "I won't add to the map" isn't good enough for the compiler - it doesn't know that you won't.