嵌套的通用集合

时间:2013-05-17 20:05:23

标签: java generics

我的代码不会陷入特定的困境,而是代表一个库,每本书都由一组包含一组单词的页面组成。

我创建了自己的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>>();

在使用像这样的通用设置时,有人可以解释一下我做错了什么吗?

3 个答案:

答案 0 :(得分:3)

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

如果你说过

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

然后那也会奏效。

答案 1 :(得分:1)

它要么

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

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

虽然WordSetSet的子类,但Set<WordSet>不是Set<Set>的子类。

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

答案 2 :(得分: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<>();
}

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