Почему значения 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());
Ответы
Ответ 1
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 #(): Проверьте тип возврата в источнике и спросите себя, может ли 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);
}
Ответ 2
Ответ можно найти, прочитав JavaDoc
Метод values()
возвращает a 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
имеет конструктор, который принимает коллекцию.
Ответ 3
Это потому, что values()
возвращает Collection
, который в соответствии с исходным кодом HashMap
имеет тип AbstractCollection
и поэтому не может быть отброшен в List
.
Вы можете создать экземпляр ArrayList
, передав его values()
result, потому что конструктор ArrayList
может принимать Collection
в качестве своего аргумента.
Ответ 4
Если вы уже создали экземпляр своего подтипа List (например, ArrayList, LinkedList), вы можете использовать метод addAll.
например.
valuesToMatch.addAll(myCollection)
Многие подтипы списка также могут брать исходный набор в свой конструктор.
Ответ 5
Вы проверяете API, что возвращается методом values()
? И что ArrayList конструктор принимает?
Ответ 6
У меня возникла одна и та же проблема. Но потом я понял, что values () возвращает Collection, а не List.
Но мы можем создать экземпляр нового ArrayList следующим образом:
Список значенийToMatch = new ArrayList (highLowValueMap.values ());
Поскольку ArrayList имеет конструктор, который может принимать в качестве аргумента Collection.
Ответ 7
Хорошо, потому что ваши ценности действительно HashSet.
Вы можете написать код, подобный этому, для перебора по набору:
List<Double> valuesToMatch=new ArrayList<>();
for(Double d : highLowValueMap.values(){
valuesToMatch.put(d);
}
Ответ 8
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
Ответ 9
Я сомневаюсь в избранном лучшем ответе, где говорится:
"Поскольку значения HashMap #() возвращают java.util.Collection, и вы не можете отбросить коллекцию в ArrayList, таким образом вы получите ClassCastException."
Не потому, что Collection не может быть передан в ArrayList, настоящая причина в том, что коллекция, возвращаемая HashMap.values (), создается внутренним классом HashMap.Values. И HashMap.Values не является суперклассом ArrayList.