why HashMap Values are not cast in List?

I'm putting values into the hashmap which is of the form,

Map<Long, Double> highLowValueMap=new HashMap<Long, Double>();
highLowValueMap.put(1l, 10.0);
highLowValueMap.put(2l, 20.0);

I want to create a list by using values() method of map.

List<Double> valuesToMatch=new ArrayList<>();
valuesToMatch=(List<Double>) highLowValueMap.values();

or

List<Double> valuesToMatch=(List<Double>) highLowValueMap.values();

However, it throws an exception:

Exception in thread "main" java.lang.ClassCastException:
java.util.HashMap$Values cannot be cast to java.util.List

But it allows me to pass it in to the creation of a list:

List<Double> valuesToMatch  = new ArrayList<Double>( highLowValueMap.values());

TL;DR

List<V> al = new ArrayList<V>(hashMapVar.values());

Explanation

Because HashMap#values() returns a java.util.Collection<V> and you can't cast a Collection into an ArrayList, thus you get ClassCastException.

I'd suggest using ArrayList(Collection<? extends V>) constructor. This constructor accepts an object which implements Collection<? extends V> as an argument. You won't get ClassCastException when you pass the result of HashMap.values() like this:

List<V> al = new ArrayList<V>(hashMapVar.values());

Going further into the Java API source code

HashMap#values(): Check the return type in the source, and ask yourself, can a java.util.Collection be casted into java.util.ArrayList? No

public Collection<V> values() {
    Collection<V> vs = values;
    return (vs != null ? vs : (values = new Values()));
}

ArrayList(Collection): Check the argument type in the source. Can a method which argument is a super type accepts sub type? Yes

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
}

The answer can be found by reading the JavaDoc

The values() method returns a Collection

So

List<Double> valuesToMatch=(List<Double>) highLowValueMap.values();

Should be

Collection<Double> valuesToMatch= highLowValueMap.values();

You can still iterate over this collection as you would a list.

http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html#values%28%29


This works:

List<Double> valuesToMatch  = new ArrayList<Double>( highLowValueMap.values() );

Because ArrayList has a constructor that accepts a collection.


It's because values() returns Collection which according to source code of HashMap is of type AbstractCollection and thus cannot be cast to List.

You are able to instantiate ArrayList passing it values() result because ArrayList constructor can take Collection as its argument.