我正在努力想出一个简单的 API due to generics not being covariant
这是我的新问题:我无法获得满足我需要的 Set<>。我尝试阅读各种指南,但它们都使用了很多我迷路的流行语。
考虑以下类
public class Parent {}
public class Child extends Parent {}
interface Store {
public Set<Parent> getParents(); //PROBLEM!! This needs to change
}
至少,我需要这些操作才能工作
Set<Parent> parents = store.getParents();
parents.add(new Parent());
parents.add(new Child());
store.getParents().add(new Child()); //Note the lack of generics
for(Parent curEntry : store.getParents()) {
}
实现 Store 的类需要能够与 Child 一起工作(意味着它们有一个 Set 是 child)。他们需要向外界公开 child 作为 parent 的身份。
尝试#1
interface Store {
public Set<Parent> getParents();
}
class ConcreteStore implements Store {
Set<Child> childs;
public Set<Parent> getParents() {
return (Set<? extends Parent>)childs; //ERROR: inconvertible types
}
}
尝试#2
interface Store {
public Set<? extends Parent> getParents();
}
class ConcreteStore implements Store {
Set<Child> childs;
public Set<Child> getParents() {
return childs;
}
}
Store store = new ConcreteStore();
Set<? extends Parent> parents = store.getParents();
parents.add(new Child()); //ERROR: cannot find symbol
parents.add(new Parent()); //ERROR: cannot find symbol. What?!
for (Parent curEntry : store.getParents()) {
}
虽然我真的很喜欢那个版本,但它意味着在 Concrete 类之外的 Set 中添加和删除是不可能的。这使它毫无用处。真正让我困惑的是,即使添加 Parent 也不起作用。
尝试#3
interface Store<T extends Parent> {
public Set<T> getParents();
}
public static class ConcreteStore implements Store<Child> {
Set<Child> childs;
@Override
public Set<Child> getParents() {
return childs;
}
}
Store store = new ConcreteStore();
Set<Parent> parents = store.getParents();
parents.add(new Parent());
parents.add(new Child());
for (Parent curEntry : store.getParents()) { //ERROR: incompatible types. Found object, requited Parent
}
请注意,在这里我知道我可以做到 Store<Child> store = new DatabaseStore()
,但由于抽象层是不可能的并且会丢失。此外,在您使用 Parent 的任何地方传递泛型看起来都很丑陋。
--
我不知道该怎么做。这样做比我想象的要复杂得多。我真的需要一些方法来获取
最佳答案
您的问题无法以您提出的形式解决。
- A
Set<Parent>
是一个集合,您可以在其中添加任何Parent
对象,你从中得到的所有对象都是Parent
对象。 - A
Set<Child>
是一个集合,您可以在其中添加任何Child
对象,你从中得到的所有对象都是Child
对象。
正如我们所见,不可能有一个对象同时实现了这两个接口(interface):如果您可以添加任何 Parent
, 你不能确定只得到 Child
从中取出物体。这意味着您的 ConcreteStore 不能说“我只有 child ”,但允许其他人将 parent 放入其中。
Java 泛型系统就是为了避免这些错误而设计的——无论编译器在哪里咆哮,你很可能做错了什么。
A
Set<? extends Parent>
是Parent
的一些未知子类型的集合.这意味着我们不能在里面放任何东西(因为我们不知道正确的类型),我们所能得到的就是Parent
。对象。A
Set<? super Child>
是Child
的一些未知父类(super class)型的集合.这意味着我们可以放一个Child
进入它,但我们不能确定我们从中得到了什么(除了Object
,它是一切的父类(super class)型)。
回到你的问题:
为您的操作
Set<Parent> parents = store.getParents();
parents.add(new Parent());
parents.add(new Child());
store.getParents().add(new Child()); //Note the lack of generics
for(Parent curEntry : store.getParents()) {
}
要工作,除了已经发布的内容之外,您不需要任何其他东西:
public class Parent {}
public class Child extends Parent {}
interface Store {
public Set<Parent> getParents();
}
但是现在不能有只有 child 的商店实现 - 因为您需要能够添加 parent 。
你可以制作Store
参数化类型:
interface Store<X extends Parent> {
public Set<X> getParents();
}
那么你会有
class ConcreteStore implements Store<Child> {
Set<Child> childs;
public Set<Child> getParents() {
return childs;
}
}
当然,这仍然不允许您将 parent 放入其中,但现在调用者可以看到这一点 - 并且可能有另一个实现 Store<Parent>
的实现,这将允许这样做。
关于java - 努力想出带有接口(interface)和通用集的 API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6323248/