чому значення HashMap не додаються до списку?


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

Однак він видає виняток:

Виняток у потоці "main" java.lang.ClassCastException:
java.util.HashMap $ Значення не можуть бути передані до java.util.List

Але це дозволяє мені передати його для створення списку:

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

5
valuesМетод повертає колекцію, а НЕ список.
Сприйняття

Відповіді:


138

TL; DR

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

Пояснення

Тому що HashMap#values()повертає a, java.util.Collection<V>і ви не можете кинути a Collectionв ArrayList, таким чином ви отримуєте ClassCastException.

Я б запропонував використовувати ArrayList(Collection<? extends V>)конструктор. Цей конструктор приймає об'єкт, який реалізується Collection<? extends V>як аргумент. Ви не отримаєте, ClassCastExceptionколи передасте результат HashMap.values()приблизно такого:

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

Заглиблення у вихідний код Java API

Значення HashMap # (): Перевірте тип повернення у вихідному коді та запитайте себе, чи 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);
}

23

Відповідь можна знайти, прочитавши 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()повертає дані, Collectionякі відповідно до вихідного коду HashMapмають тип AbstractCollectionі тому не можуть бути передані List.

Ви можете створити екземпляр ArrayListпередачі values()результату, оскільки ArrayListконструктор може взяти Collectionза аргумент.


4

Якщо ви вже створили екземпляр свого підтипу List (наприклад, ArrayList, LinkedList), ви можете скористатися методом addAll.

наприклад,

valuesToMatch.addAll(myCollection)

Багато підтипів списку також можуть взяти вихідну колекцію у своєму конструкторі.



2

Я зіткнувся з тією ж проблемою, але потім я зрозумів значення () return Collection, а не List. Але ми можемо створити новий ArrayList таким чином:

Список значеньToMatch = новий ArrayList (highLowValueMap.values ​​());

Оскільки ArrayList має конструктор, який може взяти Collection за аргумент.


1

Ну це тому, що ваші цінності насправді є HashSet. Ви можете написати такий код, щоб повторити набір:

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

Ні, values()метод повертає a Collectionі keySet()повертає a Set. docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
everton

Ви додаєте елементи до ArrrayList за допомогою add, not put, який призначений для Set.
WebComer

1

Valuesє внутрішнім класом у HashMapкласі (див. символ $ у java.util.HashMap$Values).
Метод HashMap.values ​​() поверне Valuesоб'єкт класу, який не реалізує Listінтерфейс. Так само ClassCastException.
Ось Valuesвнутрішній приватний клас у HashMap, який не реалізує 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

Ваша відповідь є найбільш зрозумілою. Я не міг зрозуміти, чому я можу це зробити, Collection<String> c = new ArrayList<>();але не міг виконати кастинг values()для цього типу чи навіть List.
ашур

@ ashur Це тому, що таким чином ви кодуєте інтерфейс, що є прийнятним. Ви можете змінити колекцію на List (оскільки це також інтерфейс) у вашому прикладі, і це все ще гаразд, але ви не можете передати інтерфейс.
WebComer

1

Я сумніваюся у вибраній найкращій відповіді, де сказано: "Оскільки HashMap # values ​​() повертає java.util.Collection, і ви не можете передати колекцію в ArrayList, таким чином ви отримуєте ClassCastException."

Це не тому, що Collection не можна передати в ArrayList, справжня причина полягає в тому, що колекція, повернута HashMap.values ​​(), резервується внутрішнім класом HashMap.Values. І HashMap.Values ​​не є суперкласом ArrayList.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.