我无法理解为什么以下内容不起作用,我确信答案与我不理解的基本内容有关,希望有人可以提供帮助。
我理解在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
并将接口作为泛型类型,为什么不能在最后一个语句中传入刀组的数组列表?
答案 0 :(得分: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
的子类的任何泛型类型。使用边界可能非常强大。这种绑定是 upper 绑定 - 我们将顶级类指定为Weapon
。
还有 lower 绑定,它使用以下语法:
List<? super Weapon> // accept any type that is a Weapon or higher in the class hierarchy
那么,何时使用每一个?记住这个词PECS
:“制片人延伸,消费者超级”。这意味着在代码的生产者端(对象创建)使用extends
,并在代码的使用者端(对象使用)我们super
。一旦你尝试了几次,你将通过经验了解为什么它运作良好。
This SO question/answer很好地涵盖了它。
答案 1 :(得分:4)
这是关于泛型的最常见问题之一。 List<Gun>
是List<Weapon>
,你可以做
List<Gun> gunList = new ArrayList<Gun>();
List<Weapon> weaponList = gunList;
weaponList.add(new Knife());
gunList.get(0).fire(); // ClassCastException
这将破坏仿制药所承诺的类型安全性。