收藏<?扩展 T> 与集合<T>

2022-09-02 12:45:48

在尝试理解Spring MVC的概念之后,我遇到了我以前从未见过的表达方式。我试图自己弄清楚,但我看到使用和之间没有区别。我猜它只允许Book的扩展,但它也允许Book。所以挠挠那个。我尝试过使用谷歌,但自从?是谷歌中的通配符,它几乎不可能搜索。我已经搜索了stackoverflow以获取答案,但是有关此问题的所有问题(例如List<?扩展了MyType>并且<?扩展>Java语法)已经假定了.以下是最初引起我兴趣的代码:Collection<? extends Book>Collection<? extends Book>Collection<Book>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);
    }
}

有什么作用?它与 有何不同?<? extends T><T>

编辑:

后续问题:是否意味着扩展?BookCase extends ArrayList<Book>BookCaseBook


答案 1

请考虑以下事项

class Animal { }
class Horse extends Animal { }

private static void specific(List<Animal> param) { }
private static void wildcard(List<? extends Animal> param) { }

如果没有扩展语法,则只能在签名中使用确切的类

    specific(new ArrayList<Horse>()); // <== compiler error

使用通配符扩展,您可以允许动物的任何子类

    wildcard(new ArrayList<Horse>());  // <== OK

通常最好使用 ?扩展语法,因为它使您的代码更易于重用和面向未来。


答案 2

和 表示一个集合,该集合可以保存可以通过 is-a 关系被视为 Book 的实例和对象。此属性也扩展到接口。Collection<Book>Collection<? extends Book>Book

这里的区别在于后一种形式被认为是有界的。根据边界,您将无法在此集合中添加或删除元素。

? extends T一个上限通配符。实际上,它描述了低端和高端的某种类型()之间的分层边界。它是包容性的,因此您可以在其中存储实例,但是如果您有其他类和接口,例如:?BookBook

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 {}

...您可以在 .Collection<? extends Book>

还记得我提到过您可能无法在此集合中添加或删除内容吗?请记住此约定:

生产者延伸;消费者超级。

请注意,这是从集合的角度出发的;如果集合以 为界,则它是生产者;如果它以 为界,则为使用者。extendssuper

也就是说,从这个系列的角度来看,它已经制作了所有的记录,所以你不能向它添加新的记录。

List<? extends Book> books = new ArrayList<>(); // permanently empty
books.add(new Book()); // illegal

如果是将 它绑定在 一起,则无法以理智的方式从中检索元素 - 您必须检索它们,这并不简洁。? super BookObject

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

首先,如果您绑定了 ,则只打算将元素插入到该集合中。? super T

后续问题:这是否意味着?BookCase extends ArrayList<Book>BookCase extends Book

否。在该实例中,A 是 一个 ,而不是 一个 。碰巧的是,数组列表绑定到存储书籍,但它本身不是 .BookCaseArrayListBookBook