it-roy-ru.com

почему значения 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());
63
bNd

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

Ответ можно найти, прочитав 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 имеет конструктор, который принимает коллекцию. 

21
cowls

Это потому, что values() возвращает Collection, который согласно исходному коду HashMap имеет тип AbstractCollection и, следовательно, не может быть приведен к List.

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

5
Andrew Logvinov

Если вы уже создали экземпляр своего подтипа List (например, ArrayList, LinkedList), вы можете использовать метод addAll.

например.,

valuesToMatch.addAll(myCollection)

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

3
user195488

Вы проверяли API, что возвращает метод values() ? А что ArrayList конструктор принимает?

2
Abimaran Kugathasan

Я столкнулся с той же проблемой, но затем я понял, что values ​​() возвращают Collection, а не List . Но мы можем создать новый ArrayList следующим образом:

List valuesToMatch = new ArrayList (highLowValueMap.values ​​());

Потому что ArrayList имеет конструктор, который может принимать Collection в качестве аргумента.

2
Jyothirmayi Lalitha

Ну, это потому, что ваши ценности действительно HashSet. Вы можете написать код, подобный этому, для перебора набора:

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

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. Теперь, какой класс реализует этот интерфейс коллекции? Ответ - класс 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
1
AmitG

Я сомневаюсь, что выбран лучший ответ, где он говорит: "Поскольку HashMap # values ​​() возвращает Java.util.Collection, и вы не можете преобразовать коллекцию в ArrayList, таким образом вы получаете ClassCastException."

Это не потому, что Collection не может быть преобразован в ArrayList, реальная причина в том, что Collection, возвращаемая HashMap.values ​​(), резервируется внутренним классом HashMap.Values. И HashMap.Values ​​не является суперклассом ArrayList.

0
Jin