ArrayList 的泛型类型和接口继承的问题

发布于 2024-12-22 11:54:16 字数 1032 浏览 1 评论 0原文

我无法理解为什么以下内容不起作用,我确信答案与我不理解的基本内容有关,希望有人可以提供帮助。

我了解如何在 ArrayList 中使用接口,这样如果我有:

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

那么您可以将任何实现 Weapon 的东西插入到武器数组中:

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

我明白了,但令我困惑的是对为什么的理解ArrayList 在其他方面与 ArrayList 不兼容。为了说明这一点,以下内容是合法的:

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,为什么不能在最后一个语句中传入刀的数组列表?

I'm having trouble understanding why the following doesn't work and I'm sure the answer is related to something basic I am not understanding and hope someone can help.

I understand about using interfaces in an ArrayList such that if I have:

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

you can then insert anything that implements Weapon into the an array of weapons:

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

I get that, but what is confusing me is the understanding of why ArrayList<Gun> isn't compatible with ArrayList<Weapon> in other ways. To illustrate, the following is legal:

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

but the following is not:

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

because the last function call reports that the method isn't applicable for its arguments.

My question is why if the method knows it tasks an ArrayList with an interface as the generic type, why isn't it okay to pass in an array list of knives in that last statement?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

黎歌 2024-12-29 11:54:16

要“修复”代码,您需要使用通用绑定

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

关键原因是List不是<的子类代码>列表<武器>。这个事实的原因可以通过以下代码来说明:

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!

通过使用绑定 ,我们是说我们将接受任何Weapon子类的泛型类型。使用边界可以非常强大。这种绑定是绑定 - 我们将顶级类指定为Weapon

还有一个使用以下语法的下限

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

那么,何时使用每一个?记住这个词PECS:“生产者扩展,消费者超级”。这意味着在代码的生产者端(创建对象的地方)使用extends,而在代码的消费者端(使用对象的地方)我们超级。一旦你尝试了几次,你就会通过经验理解为什么它效果很好。

这个问题/答案很好地涵盖了它。

To "fix" the code, you need to use a generic bound:

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

The key reason is List<Gun> is not a subclass of List<Weapon>. The reason for this fact can be illustrated by this code:

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!

By using the bound <? extends Weapon>, we are saying we'll accept any generic type that is a subclass of Weapon. Using bounds can be very powerful. This kind of bound is an upper bound - we are specifying the top-level class as being Weapon.

There's also a lower bound, that uses this syntax:

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

So, when to use each one? Remember this word PECS: "Producer extends, consumer super". This means on the producer side of the code (where the objects are created) use extends, and on the consumer side of the code (where the objects are used) us super. Once you try it a few times, you'll understand through experience why it works well.

This SO question/answer covers it well.

标点 2024-12-29 11:54:16

这是关于泛型最常见的问题之一。如果 ListList,您可以

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

这样做,这会破坏泛型所承诺的类型安全。

This is one of the most asked questions about generics. It a List<Gun> was a List<Weapon>, you could do

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

This would thus break the type-safety promised by generics.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文