Programing

HashMap 값이 목록에 캐스팅되지 않는 이유는 무엇입니까?

crosscheck 2020. 11. 4. 07:42
반응형

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 $ Values를 java.util.List로 캐스트 할 수 없습니다.

그러나 목록 생성에 전달할 수 있습니다.

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

TL; DR

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

설명

때문에 HashMap#values()반환은 java.util.Collection<V>당신이 캐스팅 할 수 CollectionArrayList따라서 당신이 얻을 ClassCastException.

ArrayList(Collection<? extends V>)생성자를 사용하는 것이 좋습니다 . 이 생성자는 Collection<? extends V>인수로 구현되는 객체를받습니다 . 다음 과 같은 ClassCastException결과를 통과하면 얻을 수 없습니다 HashMap.values().

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

Java API 소스 코드로 이동

HashMap의 # 값 () : 소스에서 반환 형식을 확인하고 자신에게 물어, (A)은 수 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);
}

대답은 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컬렉션을 받아들이는 생성자가 있기 때문 입니다.


소스 코드에 따라 유형이 있으므로으로 캐스팅 할 수없는 것을 values()반환 하기 때문 입니다.CollectionHashMapAbstractCollectionList

생성자가 인수로 사용할 수 있으므로 결과를 ArrayList전달 하여 인스턴스화 할 수 있습니다 .values()ArrayListCollection


List 하위 유형 (예 : ArrayList, LinkedList)의 인스턴스를 이미 만든 경우 addAll 메서드를 사용할 수 있습니다.

예 :

valuesToMatch.addAll(myCollection)

많은 목록 하위 유형은 생성자에서 소스 컬렉션을 가져올 수도 있습니다.


API를 확인 했습니까 values()? 메소드 가 반환하는 것은 무엇 입니까? 그리고 어떤 ArrayList 생성자가 허용합니까?


나는 같은 문제에 직면했지만 values ​​()는 List가 아닌 Collection을 반환한다는 것을 깨달았습니다. 그러나 다음과 같이 새로운 ArrayList를 인스턴스화 할 수 있습니다.

값 나열 ToMatch = new ArrayList (highLowValueMap.values ​​());

ArrayList에는 Collection을 인수로 사용할 수있는 생성자가 있기 때문입니다.


Well it's because your values are really a HashSet. You could write a code like this to iterate over the set:

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

Values is an inner class in HashMap class (see $ symbol in java.util.HashMap$Values).
HashMap.values() method will return Values class's object which is not implementing List interface. So is the ClassCastException.
Here is the Values inner private class in HashMap which is not implementing List interface. Even AbstractCollection is also not implementing List interface.
AbstractCollection implements Collection interface. So not able to cast to 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();
        }
    }

Update

Following is one of the constructor in 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);
    }

So hashmapObj.values() method return type is Collection. Now which class is implementing this Collection interface ? Answer is Values class which is inside the HashMap class (inner class). Returned value from hashmapObj.values() can be passed to above ArrayList constructor which is valid.

Even following is valid statements.

HashMap<String, String> map  = new HashMap<String, String>();
Collection c = map.values();

But following statements are incorrect

HashMap<String, String> map  = new HashMap<String, String>();
List c = map.values(); //compilation error.. return type is not List

I doubt the selected best answer, where it says: "Because HashMap#values() returns a java.util.Collection and you can't cast a Collection into an ArrayList, thus you get ClassCastException."

It's not because Collection can't be casted to ArrayList, the real reason is that the Collection returned by HashMap.values() is backed up by the inner class HashMap.Values. And HashMap.Values is not a super class of ArrayList.

참고URL : https://stackoverflow.com/questions/15522546/why-hashmap-values-are-not-cast-in-list

반응형