web-dev-qa-db-ja.com

Javaでマップの配列をどのようにインスタンス化しますか?

ジェネリックを使用してマップの配列を宣言し、マップタイプを指定できます。

private Map<String, Integer>[] myMaps;

ただし、適切にインスタンス化する方法がわかりません。

myMaps = new HashMap<String, Integer>[count]; // gives "generic array creation" error
myMaps = new HashMap[count]; // gives an "unchecked or unsafe operation" warning
myMaps = (Map<String, Integer>[])new HashMap[count]; // also gives warning

コンパイラのエラーや警告を表示せずに、このマップの配列をインスタンス化するにはどうすればよいですか?

更新:

お返事ありがとうございます。私はリストの提案に行き着きました。

34
Karl von L

厳密にはあなたの質問に対する答えではありませんが、代わりにListを使用することを検討しましたか?

List<Map<String,Integer>> maps = new ArrayList<Map<String,Integer>>();
...
maps.add(new HashMap<String,Integer>());

うまくいくようです。

配列をジェネリックと混合することが推奨されない理由の詳細な説明については、 Javaの理論と実践:ジェネリックスgotchas を参照してください。

更新:

Drewがコメントで述べたように、Listの代わりに Collection インターフェイスを使用した方が良いかもしれません。これは、Set、またはCollectionの他のサブインターフェイスの1つに変更する必要がある場合に便利です。サンプルコード:

Collection<Map<String,Integer>> maps = new HashSet<Map<String,Integer>>();
...
maps.add(new HashMap<String,Integer>());

この開始点からは、HashSetArrayListPriorityQueue、またはCollectionを実装する他のクラスに変更するだけで済みます。

38
Bill the Lizard

汎用配列を安全に作成することはできません。 Effective Java 2nd Editionは Genericsの章 の詳細に入ります。119ページの最後の段落から始めます。

汎用配列を作成するのはなぜ違法ですか?タイプセーフではないからです。正当である場合、コンパイラによって生成されたキャストは、それ以外の場合は正しいプログラムで、実行時にClassCastExceptionで失敗する可能性があります。これは、ジェネリック型システムによって提供される基本的な保証に違反します。

これをより具体的にするには、次のコードフラグメントを検討してください。

// Why generic array creation is illegal - won't compile!
List<String>[] stringLists = new List<String>[1]; // (1)
List<Integer> intList = Arrays.asList(42); // (2)
Object[] objects = stringLists; // (3)
objects[0] = intList; // (4)
String s = stringLists[0].get(0); // (5)

汎用配列を作成する1行目が正当であるとしましょう。行2は、単一の要素を含むList<Integer>を作成して初期化します。行3は、List<String>配列をObject配列変数に格納します。これは配列が共変であるため有効です。行4は、List<Integer>Object配列の唯一の要素に格納します。これは、ジェネリックが消去によって実装されるため成功します。List<Integer>インスタンスの実行時型は、単にList、およびList<String>[]インスタンスのランタイムタイプはList[]であるため、この割り当てはArrayStoreExceptionを生成しません。今は困っています。 List<Integer>インスタンスのみを保持するように宣言された配列にList<String>インスタンスを保存しました。 5行目では、この配列の唯一のリストから唯一の要素を取得します。コンパイラは取得した要素をStringに自動的にキャストしますが、Integerなので、実行時にClassCastExceptionを取得します。これを防ぐために、1行目(汎用配列を作成)はコンパイル時エラーを生成します。

配列とジェネリックはうまく結合しないため(他の理由も同様)、一般的には配列ではなくCollectionオブジェクト(特にListオブジェクト)を使用する方が適切です。

18

一般に、Javaでジェネリックと配列を混在させることはお勧めできません。ArrayListを使用することをお勧めします。

配列を使用する必要がある場合、これを処理する最善の方法は、配列の作成(例2または3)を別のメソッドに配置し、@ SuppressWarnings( "unchecked")で注釈を付けることです。

5
starblue

簡単な答えは、実際にはできないということです。

それについてのブログについては、以下を参照してください。 http://www.bloggingaboutjava.org/2006/01/Java-generics-quirks/

ブログへのコメントの1つは次のように述べています:

実際、エンジニアはそのようなアレイの作成を違法にしました。したがって、汎用クラスからの配列の作成は失敗します。 Collection.toArrayメソッドとそれに続くCast to Arrayは、コンパイル時に機能します。

これにより、実行時にArrayStoreCheckを実行できないという問題は解決されませんが、この方法でジェネリックの配列を作成できます。

Bill the Lizardが示唆したように、おそらくあなたは

List<Map<String,Integer>>
2
RHSeeger

マップの汎用配列を作成できます

  1. マップのリストを作成します。

     List<Map<String, ?>> myData = new ArrayList<Map<String, ?>>();
    
  2. 配列を初期化します。

     Map<String,?>[]myDataArray=new HashMap[myData .size()];
    
  3. リストから配列にデータを入力します。

     myDataArray=myData.toArray(myDataArry);
    
2
Ruju