我的代码不会陷入特定的困境,而是代表一个库,每本书都由一组包含一组单词的页面组成。
我创建了自己的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>>();
在使用像这样的通用设置时,有人可以解释一下我做错了什么吗?
答案 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>>();
虽然WordSet
是Set
的子类,但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<>();
}
书中的页面是线性排序的,这就是我使用列表的原因。我不确定你为什么使用套装。但无论如何,通过将集合封装在类中,您可以为客户端代码提供您希望它们使用的接口。这些可见性是故意选择的;这看起来像是一组相关的类,但您可能想要更改它们。