java 收藏<? 扩展 T> 与 Collection<T>
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28464614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Collection<? extends T> vs Collection<T>
提问by Evorlor
After trying to understand the concepts at Spring MVC, I came across the expression Collection<? extends Book>
which I have never seen before. I have tried to figure it out on my own, but I am seeing no difference between using Collection<? extends Book>
and Collection<Book>
. I was guessing that it only allowed for extensions of Book, but it does allow for Book as well. So scratch that. I have tried using Google, but since ? is a wildcard in google, it makes it nearly impossible to search for. I have searched stackoverflow for the answer, but all questions about this (such as List<? extends MyType>and <? extends > Java syntax) already assume knowledge of Collection<? extends T>
. Here is the code that has initially intrigued my interest:
在尝试理解Spring MVC的概念后,我遇到了Collection<? extends Book>
我以前从未见过的表达方式。我试图自己弄清楚,但我认为使用Collection<? extends Book>
和Collection<Book>
. 我猜它只允许 Book 的扩展,但它也允许 Book 。所以划伤那个。我曾尝试使用 Google,但从 ? 是 google 中的通配符,几乎无法搜索。我已经在 stackoverflow 中搜索了答案,但是所有关于此的问题(例如List<? extends MyType>和<? extends > Java syntax)都已经假设了Collection<? extends T>
. 这是最初引起我兴趣的代码:
import java.util.ArrayList;
import java.util.Collection;
public class Book {
public static void main(String[] args) {
BookCase bookCase1 = new BookCase();
BookCase bookCase2 = new BookCase(bookCase1);
}
}
class BookCase extends ArrayList<Book> {
public BookCase() {
}
//acts same as public BookCase(Collection<Book> c) {
public BookCase(Collection<? extends Book> c) {
super(c);
}
}
What does <? extends T>
do? How does it differ from <T>
?
有什么作用<? extends T>
?它与 有什么不同<T>
?
EDIT:
编辑:
Followup question: Does BookCase extends ArrayList<Book>
mean that BookCase
extends Book
?
后续问题:是否BookCase extends ArrayList<Book>
意味着BookCase
扩展Book
?
采纳答案by Adam
Consider the following
考虑以下
class Animal { }
class Horse extends Animal { }
private static void specific(List<Animal> param) { }
private static void wildcard(List<? extends Animal> param) { }
Without the extends syntax you can only use the exact class in the signature
如果没有扩展语法,您只能在签名中使用确切的类
specific(new ArrayList<Horse>()); // <== compiler error
With the wildcard extends you can allow any subclasses of Animal
使用通配符扩展,您可以允许 Animal 的任何子类
wildcard(new ArrayList<Horse>()); // <== OK
It's generally better to use the ? extends syntax as it makes your code more reusable and future-proof.
通常最好使用 ? 扩展语法,因为它使您的代码更具可重用性和面向未来。
回答by Makoto
Both Collection<Book>
and Collection<? extends Book>
represents a collection that can hold Book
instances and objects that can be considered to be a Book
through the is-arelationship. This property extends to interfaces as well.
双方Collection<Book>
和Collection<? extends Book>
代表的集合,可容纳Book
实例,可以被认为是一个对象Book
通过is-a的关系。此属性也扩展到接口。
The difference here is that the latter form is considered to be bounded. Depending on the bound, you would not be able to add or remove elements from this collection.
这里的区别在于后一种形式被认为是有界的。根据边界,您将无法在此集合中添加或删除元素。
? extends T
is a upper bounded wildcard. In effect, it describes a hierarchical bound between some type (?
) at the low end, and Book
at the high end. It is inclusive, so you can store instances of Book
in there, but if you had other classes and interfaces, such as:
? extends T
是一个上限通配符。实际上,它描述了?
低端和高端某种类型 ( )之间的分层界限Book
。它是包容性的,因此您可以Book
在其中存储实例,但如果您有其他类和接口,例如:
class Novella extends Book {}
class Magazine extends Book {}
class ComicBook extends Book{}
class Manga extends Magazine {}
class Dictionary extends Book {}
class ForeignLanguageDictionary<T extends Language> extends Dictionary {}
interface Language {}
...you could find any of those instances inside of a Collection<? extends Book>
.
...您可以在 a 中找到任何这些实例Collection<? extends Book>
。
Recall that I mentioned that you may not be able to add or remove things from this collection? Remember this convention:
还记得我提到您可能无法在此集合中添加或删除内容吗?记住这个约定:
Producer extends; consumer super.
生产者延伸;消费者超级。
Note that this is from the perspective of the collection; if the collection is bounded with extends
, it's a producer; if it's bounded with super
, it's a consumer.
注意,这是从集合的角度;如果集合以 为界extends
,则为生产者;如果它以 为界super
,则它是一个消费者。
That said, from this collection's perspective, it has already produced all of its records, so you cannot add new ones to it.
也就是说,从这个集合的角度来看,它已经生成了所有记录,因此您无法向其中添加新记录。
List<? extends Book> books = new ArrayList<>(); // permanently empty
books.add(new Book()); // illegal
If it were the case that you had it bound with ? super Book
, you could not retrieve elements from it in a sane way - you'd have to retrieve them as Object
instead, which isn't concise.
如果您将它绑定到? super Book
,则无法以理智的方式从中检索元素 - 您必须改为检索它们Object
,这并不简洁。
List<? super Book> books = new ArrayList<>();
books.add(new Book());
books.add(new Manga());
Book book = books.get(0); // can't guarantee what Book I get back
Chiefly, if you are bound with ? super T
, you only ever intend to insertelements into that collection.
主要是,如果您与 绑定? super T
,您只会打算将元素插入到该集合中。
Followup question: Does
BookCase extends ArrayList<Book>
mean thatBookCase extends Book
?
后续问题:
BookCase extends ArrayList<Book>
是那个意思BookCase extends Book
吗?
No. A BookCase
in that instance is an ArrayList
, not a Book
. It so happens to be the case that the array list is bound to store books, but it itself is nota Book
.
不。BookCase
在那种情况下ArrayList
,A是 an ,而不是 a Book
。这恰巧是数组列表绑定到存放图书的情况下,但它本身是不是一个Book
。
回答by Sassa
Check out thisfrom the documentation.
从文档中查看这一点。
In general, if Foo is a subtype (subclass or subinterface) of Bar, and G is some generic type declaration, it is not the case that G is a subtype of G. This is probably the hardest thing you need to learn about generics, because it goes against our deeply held intuitions.
一般来说,如果 Foo 是 Bar 的子类型(子类或子接口),而 G 是某种泛型类型声明,则 G 不是 G 的子类型。这可能是你需要学习泛型最难的事情,因为它违背了我们根深蒂固的直觉。
Take a look at the next page about wildcardstoo.
So basically when you write void doStuff(List<Book>){}
you can only do stuff to a list of Book
objects ONLY.
所以基本上当你写的时候你void doStuff(List<Book>){}
只能对一个Book
对象列表做一些事情。
NotNovel
s, notMagazine
s, notComicBook
s.
不是Novel
s,不是Magazine
s,不是ComicBook
s。
Again, this is because although Novel
extends Book
, G<Novel>
does not actually extendG<Book>
. It is not very intuitive, but the example in the documentation will help you see it.
同样,这是因为虽然Novel
extends Book
,G<Novel>
实际上并没有扩展G<Book>
。它不是很直观,但文档中的示例将帮助您看到它。
回答by vbezhenar
Here's the example that clearly shows the difference between Collection<? extends Book>
and Collection<Book>
:
下面的示例清楚地显示了Collection<? extends Book>
和之间的区别Collection<Book>
:
public class Test {
public static void main(String[] args) {
BookCase bookCase1 = new BookCase();
BookCase bookCase2 = new BookCase(bookCase1);
List<FictionBook> fictionBooks = new ArrayList<>();
BookCase bookCase3 = new BookCase(fictionBooks);
}
}
class Book {}
class FictionBook extends Book {}
class BookCase extends ArrayList<Book> {
public BookCase() {
}
//does not act same as public BookCase(Collection<Book> c) {
public BookCase(Collection<? extends Book> c) {
super(c);
}
}
that code compiles. If you change the BookCase
s constructor parameter to Collection<Book>
, this example won't compile.
该代码编译。如果将BookCase
s 构造函数参数更改为Collection<Book>
,则此示例将无法编译。
回答by phlogratos
List<Book>
is a list that may contain any book. Because there is no restriction on the kind of book, you can add any book to it.
List<Book>
是一个可能包含任何书籍的列表。因为对书的种类没有限制,您可以向其中添加任何书。
List<? extends Book>
is as well a list that contains books, but there might but further restrictions. Maybe in fact it is a List<PoetryBook>
and it may only store instances of PoetryBook
, you can only be sure that every item inside this list is a book. Because of this possible restriction you can't add any items to this list.
List<? extends Book>
也是一个包含书籍的列表,但可能有更多限制。也许实际上它是 aList<PoetryBook>
并且它可能只存储 的实例PoetryBook
,您只能确定此列表中的每个项目都是一本书。由于这种可能的限制,您不能向此列表添加任何项目。
Consider a method that takes a list of books and returns the book with the most pages.
考虑一个获取书籍列表并返回页数最多的书籍的方法。
Book getBookWithMostPages(List<? extends Book>) {
...
}
This method can be called with List<Book>
or with List<PoetryBook>
.
可以使用List<Book>
或调用此方法List<PoetryBook>
。
If you change the signature to
如果您将签名更改为
Book getBookWithMostPages(Iterable<? extends Book>) {
...
}
then it can also be used with Set<ScienceBook>
or anything that is iterable and contains books.
那么它也可以与Set<ScienceBook>
或任何可迭代且包含书籍的东西一起使用。