почему значения 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.ленг.ClassCastException:
Ява.утиль.Значения HashMap$не могут быть приведены к java.утиль.Список
но это позволяет мне передать его в создание список:
List<Double> valuesToMatch = new ArrayList<Double>( highLowValueMap.values());
9 ответов:
TL; DR
List<V> al = new ArrayList<V>(hashMapVar.values());объяснение
, потому что
HashMap#values()возвращает ajava.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 (): Проверьте тип возврата в источнике и спросите себя, Может ли a
java.util.Collectionбыть преобразован вjava.util.ArrayList? Нетpublic Collection<V> values() { Collection<V> vs = values; return (vs != null ? vs : (values = new Values())); }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); }
ответ можно найти, прочитав JavaDoc
The
values()метод возвращает aCollectionтак
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имеет конструктор, который принимает коллекция.
потому что
values()возвращаетCollectionкоторый согласно исходному кодуHashMapтипаAbstractCollectionи таким образом не может быть приведено кList.вы можете создать экземпляр
ArrayListпередав ейvalues()результат, потому чтоArrayListконструктор может взятьCollectionв качестве аргумента.
Если вы уже создали экземпляр подтипа списка (например, ArrayList, LinkedList), вы можете использовать метод addAll.
например,
valuesToMatch.addAll(myCollection)многие подтипы списка также могут принимать исходную коллекцию в своем конструкторе.
вы проверили API, что возвращается
values()способ? А какой ArrayList конструктор можно?
Я столкнулся с той же проблемой, но потом я понял, что values() возвращает коллекцию, а не список. Но мы можем создать экземпляр нового ArrayList следующим образом:
List valuesToMatch = new ArrayList (highLowValueMap.значения());
потому что ArrayList имеет конструктор, который может принимать коллекцию в качестве аргумента.
Ну это потому, что ваши значения действительно хэш-набор. Вы можете написать такой код, чтобы перебирать набор:
List<Double> valuesToMatch=new ArrayList<>(); for(Double d : highLowValueMap.values(){ valuesToMatch.put(d); }
Valuesвнутренний классHashMapкласс (см. символ $ вjava.util.HashMap$Values).
HashMap.values () метод вернетValuesобъект класса, который не реализует . Так же как иClassCastException.
Вот этоValuesвнутренний частный класс в HashMap, который не реализует . Даже AbstractCollection также не реализует .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. Теперь какой класс реализует этот интерфейс коллекции ? Ответ: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
Я сомневаюсь в выбранном лучшем ответе, где говорится: "Потому что HashMap#values() возвращает java.утиль.Коллекция и вы не можете привести коллекцию в ArrayList, таким образом, вы получаете ClassCastException."
Это не потому, что коллекция не может быть приведена к ArrayList, реальная причина заключается в том, что коллекция возвращается HashMap.значения() опирается на внутреннее хранилище HashMap класса.Ценности. И HashMap.Значения это не супер класс коллекции ArrayList.