List中的Java泛型返回从多个接口继承的方法返回类型

时间:2017-11-15 17:31:32

标签: java generics

我目前在一家拥有各种模块的公司工作。在那家公司,如果你想提供模块内部,你可以通过java接口提供它,它隐藏了实际的实现类型,并为请求模块提供了一个接口。现在我希望有一个提供程序能够为多个模块提供数据,这些模块公开了实际内部数据的不同字段或方法。

因此我有一个内部Object,它有一些数据,我有一个接口,每个模块需要访问一些但不是严格的所有字段。最后,我有一个外部对象实现所有这些接口,并保存内部对象的实例以委托方法调用:

public class InternalObject {
    public int getA() { return 0; }
    public int getB() { return 0; }
}

public interface ModuleXObject {
   int getA();
}

public interface ModuleYObject {
    int getA();
    int getB();
}

public class ExternalObject implements ModuleXObject, ModuleYObject {
    private InternalObject _internal;

    public int getA() { return _internal.getA(); }
    public int getB() { return _internal.getB(); }
}

现在这一切都很好,但是如果我想提供 - 让我们说 - 用于查找为正确模块键入的所述对象列表的存储库方法,我遇到了如何实现这一点的问题。我希望得到以下内容:

public interface ModuleXObjectRepository {
    List<ModuleXObject> loadAllObjects();
}

public interface ModuleYObjectRepository {
    List<ModuleYObject> loadAllObjects();
}

public class ExternalObjectRepository implements ModuleXObjectRepository, ModuleYObjectRepository {
    public List<ExternalObject> loadAllObjects() {
        // ...
    }
}

这不会编译说返回类型不兼容。 所以我的问题是,如果有可能实现类似的东西,如果,如何?

我应该注意到,我尝试了一些不同的方法,我想包括它们的完整性并描绘它们的缺点(在我看来)。

方法1

public interface ModuleXObjectRepository {
    List<? extends ModuleXObject> loadAllObjects();
}

public interface ModuleYObjectRepository {
    List<? extends ModuleYObject> loadAllObjects();
}

public class ExternalObjectRepository implements ModuleXObjectRepository, ModuleYObjectRepository {
    public List<ExternalObject> loadAllObjects() {
        // ...
    }
}

这种方法与我希望的解决方案非常接近,但会产生如下代码:

List<? extends ModuleXObject> objects = repository.loadAllObjects();

因此要求用户包含&#34;?延伸&#34;关于调用loadAllObjects()的每个List-Declaration。

方法2

public interface ModuleXObjectRepository {
    List<ModuleXObject> loadAllObjects();
}

public interface ModuleYObjectRepository {
    List<ModuleYObject> loadAllObjects();
}

public class ExternalObjectRepository implements ModuleXObjectRepository, ModuleYObjectRepository {
    public List loadAllObjects() {
        // ...
    }
}

这种方法只省略了ExternalObjectRepository中的泛型,因此在我看来太过于减少了类型安全性。此外,我还没有测试过这是否真的有效。

只是为了重新编写,是否有任何可能的方法来定义loadAllObjects方法,使用户能够获得使用各自模块的对象键入的列表,而不用

  • 要求&#34;?延伸&#34;在用户代码中
  • 降低存储库实现中的类型安全性
  • 使用class / interface level generics

1 个答案:

答案 0 :(得分:0)

允许将其键入List<ModuleXObject>的挑战是其他代码可以保留为List<ExternalObject>

所有ExternalObject个实例都是ModuleXObject个实例,但反之则不然。

考虑以下附加课程:

public class MonkeyWrench implements ModuleXObject{
    //STUFF
}

MonkeyWrench个实例不是ExternalObject个实例,但是如果可以将List<ExternalObject>强制转换为List<ModuleXObject>,则可以向此集合添加MonkeyWrench个实例,这样导致运行时类转换异常和废墟类型安全的风险。

其他代码非常容易:

for(ExternalObject externalObject:externalObjectRepository.loadAllObjects())

如果其中一个实例是MonkeyWrench实例,则运行时类转换,这是泛型要避免的。

? extends ModuleXObject的含义是你可以从集合中读取任何对象ModuleXObject但是你不能向集合中添加任何东西,因为其他代码可能对集合有额外的约束。在编译时不明显/可用。

我建议您使用? extends ModuleXObject,因为它的语义似乎与您想要的一致,即拉出ModuleXObject个实例,例如。

ModuleXObjectRepository repo = //get repo however
for(ModuleXObject obj : repo.loadAllObjects()){
    //do stuff with obj
}