2011-12-23 5 views
7

次のコードが機能しない理由を理解していないため、答えが基本的なものと関連していると思います。ArrayListとインタフェース継承のジェネリック型の問題

私は私が持っている場合よう ArrayListにインターフェースを使用することについて理解

public interface Weapon { ... } 
public class Gun implements Weapon { ...} 
public class Knife implements Weapon { ... } 

をあなたが武器の配列に武器を実装して何かを挿入することができます。

ArrayList<Weapon> weapons = new ArrayList<Weapon>(); 
weapons.add(new Gun()); 
weapons.add(new Knife(); 

私がすることを得ますしかし、私が混乱しているのは、ArrayList<Gun>ArrayList<Weapon>と他の方法で互換性がない理由の理解です。

public void interfaceIsTheArgument(Weapon w) { ... } 
... 
interfaceIsTheArgument(new Gun()); 
interfaceIsTheArgument(new Knife()); 

が、以下ではありません:説明するために、次は合法である

public void interfaceIsTheArgument(ArrayList<Weapon> w) { ... } 
... 
interfaceIsTheArgument(new ArrayList<Gun>()); 
interfaceIsTheArgument(new ArrayList<Knife>()); 

最後の関数呼び出しは、メソッドは、その引数には適用されないことを報告するため。

私の質問では、メソッドがジェネリック型のインターフェイスを持つArrayListのタスクを知っている場合、その最後のステートメントのナイフの配列リストを渡すのはなぜ大丈夫ですか?

+1

私は正確な答えは分かりませんが、2番目の例でできることは 'public void interfaceIsTheArgument(ArrayList <?extends Weapon>)です。それは動作します。 – fge

答えて

13

コードを「修正」するために、あなたはバインドジェネリックを使用する必要があります。

public void interfaceIsTheArgument(List<? extends Weapon> w) { ... } 
... 
interfaceIsTheArgument(new ArrayList<? extends Weapon>()); 
interfaceIsTheArgument(new ArrayList<Knife>()); 

主な理由はList<Gun>では、List<Weapon>のサブクラスではありません。この事実の理由は、このコードによって示すことができる。

List<Gun> guns = new ArrayList<Gun>(); 
// If List<Weapon> was a super type of List<Gun>, this next line would be allowed 
List<Weapon> weapons = guns; // Won't compile, but let's assume it did 
weapons.add(new Knife()); // Compiles, because Knife is a Weapon 
Gun gun = guns.get(0); // Oops! guns.get(0) is a Knife, not a Gun! 

バウンド<? extends Weapon>を使用することにより、我々はサブクラスWeaponある任意のジェネリック型を受け入れるだろうと言っています。境界を使うことは非常に強力です。この種のバインドはの上位にバインドされています。最上位クラスをWeaponとして指定しています。

もあります拘束、この構文を使用していること:

List<? super Weapon> // accept any type that is a Weapon or higher in the class hierarchy 

だから、それぞれのいずれかを使用するには? PECSという単語を覚えています。これは、コードのプロデューサ側(オブジェクトがの場合は)はextends、コードのコンシューマ側(オブジェクトがの場合はの場合)、superとなります。一度それを数回試してみると、なぜそれがうまくいくのか経験を通して理解するでしょう。

This SO question/answerがそれをよくカバーします。

4

これは、ジェネリックに関するよくある質問です。それはList<Gun>は、あなたは、このようにジェネリック医薬品が約束型の安全性を破る

List<Gun> gunList = new ArrayList<Gun>(); 
List<Weapon> weaponList = gunList; 
weaponList.add(new Knife()); 
gunList.get(0).fire(); // ClassCastException 

これを行うことができ、List<Weapon>ました。