2016-09-28 13 views
2

私はjava genericsの新機能で、次の問題に直面しています。 私は細かい作業この1 なぜHashMap <String、Object>はHashMap <String、List>インスタンスを受け付けませんか?

  • fillDescriptiveData(ObjectMap,"here");

    HashMap<String, Object> ObjectMap = new HashMap<String, Object>(); 
    HashMap<String, List> listMap = new HashMap<String, List>(); 
    
    方法

    以下のようにAPIを呼び出す場合、私は、のようなメソッドを持っている今

    private static void fillDescriptiveData(HashMap<String, Object> output, String attributeMapping) { 
        for (Map.Entry<String, Object> outputInEntry : output.entrySet()) { 
         String outputKey = outputInEntry.getKey(); 
         String outputValue = outputInEntry.getValue().toString(); 
         outputValue = getDescriptiveDataForOutput(outputKey, outputValue, attributeMapping); 
         outputInEntry.setValue(outputValue); 
        } 
    } 
    

    を持っています。

  • fillDescriptiveData(listMap,"here"); このコール

型CustomAttributeにおける方法fillDescriptiveData(ハッシュマップ、文字列)の引数(HashMapの文字列) `

には適用されないエラーを与えますどうして ?私は1つの以上の問題に遭遇し、この問題を解決するために、行に

private static void fillDescriptiveData(HashMap<String, ? extends Object> output, String attributeMapping) { 
    for (Map.Entry<String, ? extends Object> outputInEntry : output.entrySet()) { 
     String outputKey = outputInEntry.getKey(); 
     String outputValue = outputInEntry.getValue().toString(); 
     outputValue = getDescriptiveDataForOutput(outputKey, outputValue, attributeMapping); 
     outputInEntry.setValue(outputValue); /* Error comes at this line */ 
    } 
} 

HashMap<String, ? extends Object> ObjectMap = new HashMap<String, Object>(); 
HashMap<String, List> listMap = new HashMap<String, List>(); 
fillDescriptiveData(ObjectMap,"here"); 
fillDescriptiveData(listMap,"here"); 

線にエラー - outputInEntry.setValue(outputValue);

メソッドSetValue(?キャプチャ#4のオブジェクトを拡張)にタイプ のMap.Entryは 引数(文字列)

理由には適用されませんか?

この問題を避けるにはどうすればよいですか?

+1

あなたの第二の "なぜ?"私はなぜString型の値を 'Map 'に入れることができないのですか?答えは "静的型システムがその仕事をしているからです" –

+2

あなたがしようとしていることは、あなたのメソッド 'fillDescriptiveData'は' HashMap を違反である 'HashMap 'に変換し、ジェネリックを使用せず、トマトを変換したい場合は単純にraw型を使用しますニンジンに入れて結果を同じコレクションに入れる –

+0

Map getDescriptiveData(HashMap output、String attributeMapping){...} 'のようなものはどうですか? – JimmyB

答えて

2

あなたは型変数を使用することができたときにこれがケースである:

private static <T> void fillDescriptiveData(Map<String, T> output,String attributeMapping) 
{ 
    for(Map.Entry<String, T> outputInEntry : output.entrySet()) 
    { 
     String outputKey = outputInEntry.getKey(); 
     String outputValue = outputInEntry.getValue().toString(); 
     outputValue = getDescriptiveDataForOutput(outputKey, outputValue, attributeMapping); 
     outputInEntry.setValue((T) outputValue); 
    } 
} 

具体的には、マップ内の2番目の型パラメータは無制限です。 Objectは特定のクラスとしてここでは機能しません。 ? extends Objectは多少ナンセンスです。 ちょうどHashMap<String, ?>が地図を読むまで動作しますが、ここに何かを置くことはできません。したがって、一方向のみ - 型変数を使用します。

EDIT:さらにもう1つ:可能な限りインターフェイスを使用してください。ここではHashMap<String, T>の代わりにMap<String, T>を使用してください。間違いではなく、適切で適切なスタイルのコードです。

+0

'string outputValue'が任意の' T'にキャスト可能であることを期待しているようです。 –

+0

@MarkoTopolnik私は同意します。これは非常に奇妙ですが、私はそれに気づいていませんでした。実行時には、任意の値マップへ: – Andremoniy

+0

意味のあるメソッドシグネチャは 'Map マップ、T値) 'であるが、これはOPの目的ではないようだ。彼はかなり気が利いたものに向かっているようだ。 –

1

この行でエラー:

outputInEntry.setValue(outputValue); 

は、常にエントリに文字列を入れているということです。これは、エントリのタイプが? super String、またはStringの場合にのみ有効です。したがって、Map<String, Object>またはMap<String, List>の場合は機能しません。

各値を文字列にマップしたいと思うようです。あなたはそれを行うことができますが、タイプセーフであるためには、新しいMap<String, String>を作成する必要があります。あなたは常にStringにマッピングされているので

たとえば、Map<String, List<?>>を渡して、すべての値を文字列で置き換えてください(安全でない場合)。誰かが関数に渡されたMap<String, List<?>>を引き続き使用することができましたが、リストの代わりに値として文字列が含まれています。彼らがListを取得しようとすると、クラスキャスト例外が発生します。このような

何か:

private static Map<String, String> fillDescriptiveData(HashMap<String, ?> input, 
     String attributeMapping) {   
    Map<String, String> output = new HashMap<>(); 

    for(Entry<String, ?> e : input.entrySet()) { 
      String outputKey = e.getKey(); 
      String outputValue = e.getValue().toString(); 
      outputValue 
       = getDescriptiveDataForOutput(outputKey, outputValue, attributeMapping); 
      output.put(outputKey, outputValue); 
    } 
    return output; 
} 
Map<String, String> r1 = fillDescriptiveData(ObjectMap, "here"); 
Map<String, String> r2 = fillDescriptiveData(listMap, "here"); 
+0

このステートメントは "これはうまくいく"とは正確ではありません。私は私の答えで言ったように、それは変数の型で動作します。ランタイムマップではどの型の値も保持できるので、タイプの実際のミスマッチは重大な問題ではありません – Andremoniy

+0

@Andremoniyもちろん、「適切に」または「型の安全な方法で」追加する必要があります。 –

関連する問題