为什么HashMap值不转换为List?


77

我正在将值放入形式的哈希图中,

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

我想通过使用values()map方法创建一个列表。

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

要么

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

但是,它将引发异常:

线程“主”中的异常java.lang.ClassCastException:
java.util.HashMap $ Values无法转换为java.util.List

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

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

5
values方法返回一个集合,而不是一个列表。
感知

Answers:


135

TL; DR

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

说明

因为HashMap#values()返回ajava.util.Collection<V>并且您不能将a强制Collection转换为an ArrayList,因此得到ClassCastException

我建议使用ArrayList(Collection<? extends V>)构造函数。此构造函数接受一个实现Collection<? extends V>为参数的对象。ClassCastException通过这样的结果,您将不会得到HashMap.values()

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

进一步研究Java API源代码

HashMap#values():检查源代码中的返回类型,并问自己,是否可以将ajava.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);
}

22

可以通过阅读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有一个接受集合的构造函数。


5

这是因为根据源代码类型values()返回的返回值不能转换为。CollectionHashMapAbstractCollectionList

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


3

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

例如,

valuesToMatch.addAll(myCollection)

许多列表子类型也可以在其构造函数中使用source集合。



2

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

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

因为ArrayList具有可以将Collection作为其参数的构造函数。



1

Values是类中的内部类HashMap(请参见中的$符号java.util.HashMap$Values)。
HashMap.values()方法将返回 Values未实现List接口的类的对象。也是ClassCastException
这是ValuesHashMap中未实现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接口?答案是ValuesHashMap类(内部类)内部的类。返回的值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

您的答案是最容易理解的。我不明白为什么我可以做,Collection<String> c = new ArrayList<>();但不能转换values()为这种类型,甚至List
ashur 2014年

@ ashur这是因为您可以通过这种方式对接口进行编码,这是可以接受的。您可以在示例中将Collection更改为List(因为它也是一个界面),它仍然可以,但是不能强制转换为interface。
WebComer

1

我对所选的最佳答案表示怀疑,因为它说:“因为HashMap#values()返回java.util.Collection,并且您不能将Collection转换为ArrayList,因此会得到ClassCastException。”

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.