web-dev-qa-db-ja.com

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

ただし、例外がスローされます。

スレッド「メイン」Java.lang.ClassCastExceptionの例外:
Java.util.HashMap $ ValuesをJava.util.Listにキャストできません

しかし、リストの作成にそれを渡すことができます:

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

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>を実装するオブジェクトを引数として受け入れます。次のようにHashMap.values()の結果を渡すと、ClassCastExceptionを取得できません。

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

Java AP​​Iソースコードにさらに進む

HashMap#values():ソースの戻り値の型を確認し、自問してください。Java.util.CollectionJava.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);
}
116
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にはコレクションを受け入れるコンストラクターがあるためです。

22
cowls

values()Collectionを返すのは、HashMapのソースコードによると、AbstractCollection型であり、Listにキャストできないためです。

ArrayListコンストラクターはその引数としてArrayListを取ることができるため、Collectionを渡すことでvalues()結果をインスタンス化できます。

5
Andrew Logvinov

Listサブタイプ(ArrayList、LinkedListなど)のインスタンスを既に作成している場合は、addAllメソッドを使用できます。

例えば。、

valuesToMatch.addAll(myCollection)

多くのリストサブタイプは、コンストラクターでソースコレクションを取ることもできます。

3
user195488

values() メソッドが返すAPIを確認しましたか?そして、ArrayList constructor は何を受け入れますか?

2

同じ問題に直面しましたが、その後、values()はListではなくCollectionを返すことに気付きました。ただし、次のように新しいArrayListをインスタンス化できます。

リストの値ToMatch = new ArrayList(highLowValueMap.values());

ArrayListには、引数としてCollectionを取ることができるコンストラクターがあるためです。

2

それは、値が実際に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のコンストラクターの1つです。

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インターフェースを実装していますか?答えは、HashMapクラス(内部クラス)内にあるValuesクラスです。 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を返すため、CollectionをArrayListにキャストできないため、ClassCastExceptionが発生するため、選択したベストアンサーを疑います。」

CollectionをArrayListにキャストできないからではありません。実際の理由は、HashMap.values()によって返されるCollectionが内部クラスHashMap.Valuesによってバックアップされるためです。また、HashMap.ValuesはArrayListのスーパークラスではありません。

0
Jin