0

在不拘泥于细节的情况下,我的代码代表了一个库,其中每本书都由一组包含一组单词的页面组成。

我创建了自己的 Set 实现:

class PageSet<E> extends HashSet<E>(){
    public boolean set(int index, E e){....}
    ....
}

class WordSet<E> extends HashSet<E>(){
    public boolean set(int index, E e){....}
    ....
}

当我尝试在我的主类中创建一本书时,我遇到了困难:

Set<Set<Word>> dictionary = new PageSet<WordSet<Word>>();

这导致类型转换不匹配。但是它会很高兴地接受

Set<Set<Word>> dictionary = new PageSet<Set<Word>>();

在使用这样的通用设置时,有人可以说明我做错了什么吗?

4

3 回答 3

3

基本上, aPageSet<WordSet<Word>>不是 a Set<Set<Word>>,因为X<Subclass>不是 a X<Superclass>

如果你说过

Set<WordSet<Word>> dictionary = new PageSet<WordSet<Word>>();

那么这也行得通。

于 2013-05-17T20:07:53.437 回答
1

要么是

Set<Set<Word>> dictionary = new PageSet<Set<Word>>();

或者

Set<WordSet<Word>> dictionary = new PageSet<WordSet<Word>>();

因为虽然WordSet是 的子类Set,但 aSet<WordSet>不是 的子类Set<Set>

换句话说,泛型不是协变的,这与数组之类的东西不同。

于 2013-05-17T20:09:00.027 回答
0

在任何情况下,除非您尝试创建新的集合类型,否则不应扩展集合。由于您不能限制子类中超类方法的可见性,因此人们将能够编写

WordSet<Word> words = ...;
words.clear();

您可能不想给客户这种权力。相反,使用聚合而不是继承。

class Word {
    private String text;
    private PartOfSpeech part;
    // Constructors, getters, setters, equals, hashCode are elided.
}

class Page {
    private int pageNumber;
    private Set<Word> contents = new HashSet<>();

public class Book {
    private String title;
    private List<Page> pages = new ArrayList<>();
}

书中的页面是线性排序的,这就是我使用列表的原因。我不确定你为什么使用套装。但无论如何,通过将集合封装在类中,您可以为客户端代码提供您希望它们使用的接口。能见度是故意选择的;这看起来像一个相关类的集群,但您可能想要更改它们。

于 2013-05-17T20:31:45.703 回答