java - 努力想出带有接口(interface)和通用集的 API

标签 java generics

我正在努力想出一个简单的 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/

相关文章:

java - 如何测试某种输入格式

PowerShell:无法过滤通用列表的特殊情况

java - 如果main方法被参数化了,那么如何指定它的真实类型呢?

scala - 如何在scala中设置类型参数绑定(bind)来为数字创建泛型函数?

generics - 如何将外部关联类型强制为我的本地结构类型?

java - 如何将 boolean 数组的特定字段设置为 false

java - 如何在Android中使用Settings.Global类

java - EditText 如何占据布局中的所有剩余空间?

c# - 通用参数的动态长度

java - 保存 HLS 流?