为什么HashMap值不在List中强制转换?

时间:2013-03-20 11:41:51

标签: java arraylist collections hashmap

我将值放入形式为

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

我想使用values()地图方法创建一个列表。

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

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

然而,它引发了一个例外:

  

线程“main”中的异常java.lang.ClassCastException:
  java.util.HashMap $不能将值强制转换为java.util.List

但它允许我将其传递给列表的创建:

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

10 个答案:

答案 0 :(得分:113)

TL; DR

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

解释

由于HashMap#values()返回java.util.Collection<V>而您无法将Collection投放到ArrayList,因此您获得了ClassCastException

我建议使用ArrayList(Collection<? extends V>)构造函数。此构造函数接受一个实现Collection<? extends V>作为参数的对象。当您传递ClassCastException的结果时,您将无法获得HashMap.values()

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

进一步了解Java API源代码

HashMap#values():检查来源中的返回类型,并问问自己,java.util.Collection是否可以投放到java.util.ArrayList?否

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

ArrayList(Collection):检查源中的参数类型。参数是超类型的方法可以接受子类型吗?是

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);
}

答案 1 :(得分:21)

通过阅读JavaDoc

可以找到答案

values()方法返回Collection

所以

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

应该是

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

您仍然可以像列表一样迭代此集合。

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


这有效:

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

因为ArrayList有一个接受集合的构造函数。

答案 2 :(得分:5)

这是因为values()返回Collection根据HashMap的源代码属于AbstractCollection,因此无法转换为List

您可以实例化ArrayList传递values()结果,因为ArrayList构造函数可以将Collection作为参数。

答案 3 :(得分:3)

如果您已经创建了List子类型的实例(例如,ArrayList,LinkedList),则可以使用addAll方法。

如,

valuesToMatch.addAll(myCollection)

许多列表子类型也可以在其构造函数中获取源集合。

答案 4 :(得分:2)

您是否检查了API,values()方法返回了什么? ArrayList constructor接受什么?

答案 5 :(得分:2)

我遇到了同样的问题,但后来我意识到values()返回Collection,而不是List。 但是我们能够像这样实例化一个新的ArrayList:

列出valuesToMatch = new ArrayList(highLowValueMap.values());

因为ArrayList有一个构造函数,可以将Collection作为参数。

答案 6 :(得分:1)

好吧,因为你的值实际上是一个HashSet。 您可以编写这样的代码来迭代集合:

List<Double> valuesToMatch=new ArrayList<>();
for(Double d : highLowValueMap.values(){
  valuesToMatch.put(d);
}

答案 7 :(得分:1)

ValuesHashMap类中的内部类(请参阅java.util.HashMap$Values中的$符号)。
 HashMap.values()方法将返回Values类的对象,该对象未实现List接口。 ClassCastException也是如此。
这是HashMap中的Values内部私有类,它没有实现List接口。甚至AbstractCollection也没有实现List接口 AbstractCollection实现Collection接口。所以无法转换为List

private final class Values extends AbstractCollection<V> {
        public Iterator<V> iterator() {
            return newValueIterator();
        }
        public int size() {
            return size;
        }
        public boolean contains(Object o) {
            return containsValue(o);
        }
        public void clear() {
            HashMap.this.clear();
        }
    }

<强>更新

以下是ArrayList中的构造函数之一。

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);
    }

因此hashmapObj.values()方法返回类型为Collection。现在哪个类实现了这个Collection接口?答案是Values类,它位于HashMap类(内部类)中。从hashmapObj.values()返回的值可以传递给上面有效的ArrayList构造函数。

即使以下是有效的陈述。

HashMap<String, String> map  = new HashMap<String, String>();
Collection c = map.values();

但以下陈述不正确

HashMap<String, String> map  = new HashMap<String, String>();
List c = map.values(); //compilation error.. return type is not List

答案 8 :(得分:0)

我怀疑所选择的最佳答案,它说: “因为HashMap#values()返回一个java.util.Collection,你不能将一个Collection转换为ArrayList,因此你得到ClassCastException。”

这不是因为Collection无法转换为ArrayList,真正的原因是HashMap.values()返回的Collection由内部类HashMap.Values备份。而HashMap.Values不是ArrayList的超类。

答案 9 :(得分:0)

要将值从 Map 实例转换为列表,您可以使用 Iterable<T>.map

val yourList: List<Any> = #Map.values.map { it }