2010-12-18 13 views
4

Javaジェネリックスとコレクションに関する質問があります。あなたのコードの残りの部分を壊す心配Listのタイプを変更していない可能性があるためJavaジェネリックスとコレクション

List<String> catNames = new ArrayList<String>(); 

:このようなコレクションを宣言することは良い習慣と考えられています。私はこれを行うにしようとすると、しかし:

private static Map<IssueType, List<Issue>> orphanedAttrMap = new HashMap<IssueType, ArrayList<Issue>>(); 

javacはまた

Type mismatch: cannot convert from HashMap<ResultsAggregator.IssueType,ArrayList<Issue>> to HashMap<ResultsAggregator.IssueType,List<Issue>> 

を文句を、これは完全に合法である:さらに混乱思わ

private static Map<IssueType, List<Issue>> orphanedAttrMap = new HashMap<IssueType, List<Issue>>(); 

Listはインターフェイスであるため、具体的なクラスではありません。何が起きてる?これはタイプ消去の問題ですか?

答えて

8

このようなコードをコンパイルする法的だった場合、あなたはこそこそHashMapに他の種類の要素を挿入することができましたでしょう:

HashMap<IssueType, List<Issue>> a = new HashMap<IssueType, ArrayList<Issue>>(); 
a.put(someIssue, new SomeClassThatImplementsListOfIssueButIsNotArrayList()); 

何を期待されていません。 ArrayList<String>List<String>ですが、このコードでは安全で正しいとは言えません。安全のためにはList<String>ArrayList<String>とする必要があります。つまり、ジェネリック型の引数はここでは共変しません。

あなたの最後のコードは、タイプパラメータが具象クラスである必要がないため、正当です。同様に、フィールドは抽象型である必要はありません。

+0

しかし、それが「優れた実践」と考えられる最初のケースでは当てはまりませんか? –

+0

ああ、私はそれを得る、それは奇妙なことだ... –

+1

@Amir:いいえ、そうではありません。最初の行は 'List '型の1つの変数を宣言しています。その変数に他のリストを後で割り当てると、インスタンスが完全に置き換えられます。 'ArrayList'の中で*何かを変更していません。あなたはその行で何か悪いことをすることはできません。 –

4

2番目の例では、ArrayListを指定する理由はありません。それは実際にはリストを作成しないので、とにかくインターフェースをそこに置くのが最善です。あなたは後で次のことをうまく呼び出すことができます。

Map<IssueType, List<Issue>> orphanedAttrMap = new HashMap<IssueType, List<Issue>>(); 

orphanedAttrMap.put(IssueType.TYPE, new ArrayList<Issue>()); 
+0

これはより良いアプローチですか、またはLHSをArrayListとして宣言する方が良いでしょう? –

+0

@Amir、これは、このマップを使用するコードが、Listインターフェイスの一部ではないArrayList(例えばensureCapacity())のものに依存しない限り、より良いアプローチです。そして、さらにそれをListとして残し、 'if(... instanceof ...)'を使用し、実際に必要なArrayListメソッドにアクセスするためにダウンキャストすることをお勧めします。インターフェイスの使用は、コンクリートクラスを使用するよりも、ほとんど常に優れています。 –

関連する問題