获取-放置原则的解释

88
我已经阅读了O'Reilly的书,其中我了解到了“获取-放置原则”。
  • 当你只想从结构中获取值时,请使用extends通配符。
  • 当你只想向结构中放置值时,请使用super通配符。
  • 如果你既想获取又想放置值,请不要使用通配符。
例外情况是:
  • 在使用extends通配符声明的类型中,除了null(它属于每个引用类型),您不能放置任何内容。

  • 在使用super通配符声明的类型中,除了Object类型的值(它是每个引用类型的超级类型)之外,您不能获取任何内容。

请问有人能够帮我深入探讨一下这个规则吗?如果可能的话,请按层次结构排列。

5
+1:总是很高兴看到有人在基础上寻求澄清。 - Everyone
2
大家好,我想你是指基础意义上的根本而不是背侧? - Rich Seller
1个回答

179
考虑一堆香蕉。这是一个Collection<? extends Fruit>,因为它是一组特定种类的水果集合,但是您不知道(从该声明中)它是哪种水果的集合。您可以从中获取一个项目并知道它肯定是水果,但您无法添加到其中 - 您可能正在尝试将苹果添加到一堆香蕉中,这绝对是错误的。您可以向其中添加null,因为对于任何类型的水果,它都将是有效值。
现在考虑一个装水果的碗。这是一个Collection<? super Banana>,因为它是某种“大于”Banana类型的集合(例如Collection<Fruit>Collection<TropicalFruit>)。您可以确实向其中添加香蕉,但如果您从碗中获取一个项目,您不知道会得到什么 - 它很可能不是香蕉。您唯一确定的是它将是一个有效(可能为null)的Object引用。
(通常情况下,对于Java泛型问题,Java Generics FAQ是一个非常好的资源,其中包含您可能要提出的几乎所有与泛型相关的答案。)

6
正是因为这个原因,Java会防止你向“Collection<? extends Fruit>”中添加除null以外的任何东西,并且你必须明确地强制转换获取项目的结果,也正是出于这些原因。 - Jon Skeet
@JonSkeet 这可能是一个愚蠢的问题,但在什么情况下不拥有add()和get()方法会很有用呢?我的意思是,要从列表中获取某个对象,您必须首先将其添加,对吧?反之亦然,如果之后无法获取它,为什么要添加它呢? - Timmos
7
@Timmos说:“仅仅因为某些代码需要添加值,不意味着所有的代码都需要这样做。例如,为了显示人名列表,我可能只需要一个Collection<? extends Person>(或更可能是一个Iterable<? extends Person>,但是…)。创建该集合的代码可能需要它是一个Collection<Employee>,但消费该代码的代码并不需要这样做。” - Jon Skeet
@JonSkeet 好的,我明白了。所以这是一种保护机制? - Timmos
5
@Timmos说:“在这种情况下,你需要确切地说明你所说的‘it’是什么……但是是的,Java泛型规则旨在提供类型安全性。” - Jon Skeet
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接