本文介绍了List中的Java泛型返回从多个接口继承的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

因此,我有一个内部对象,其中有一些数据,我有一个需要访问一些但不是所有字段的每个模块的接口。最后,我有一个实现所有这些接口的外部对象,并持有内部对象的一个​​实例来委托方法调用:

  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<扩展ModuleXObject> loadAllObjects();
}

公共接口ModuleYObjectRepository {
列表< ;?扩展ModuleYObject> loadAllObjects();
}

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

这种方法与我更喜欢的解决方案非常接近,但是会得到如下代码:

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

因此,要求用户在每个List-Declaration中包含?extends loadAllObjects()。



方式2

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

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

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

这种方法只是省略了ExternalObjectRepository中的泛型,因此我认为这会降低类型安全性。此外,我还没有测试过,如果这实际上工作。






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


  • 要求在用户代码中使用?extends
  • 在存储库实现中降低类型安全性
  • 使用类/接口级别泛型 $


解决方案

允许将其输入为 List< ModuleXObject> 是其他代码可以保存为 List< ExternalObject> 。



全部 ExternalObject 实例是 ModuleXObject 实例,但反过来不是这样。



考虑下面的附加类:

  public class MonkeyWrench implements ModuleXObject {
// STUFF
}

MonkeyWrench 实例不是 ExternalObject 个实例,但是如果可以将 List< ExternalObject> 转换为 List< ModuleXObject> 可能会向此集合添加 MonkeyWrench 实例,这会导致运行时类转换异常的风险,并且会破坏类型安全性。



$ b

  for(ExternalObject externalObject:externalObjectRepository.loadAllObjects())

code>

如果其中一个实例是 MonkeyWrench 实例,则运行time class cast ,这是泛型意味着避免的。

的含义?扩展ModuleXObject 是您可以从集合中读取任何对象作为 ModuleXObject ,但不能向其他代码添加任何内容

在你的情况下,我建议使用?扩展ModuleXObject ,因为它的语义看起来与您想要的一致,即拉出 ModuleXObject 实例,例如

  ModuleXObjectRepository repo = //获取回购但是
for(ModuleXObject obj:repo.loadAllObjects()){
//用obj $ b做东西$ b}


I'm currently working at a company that has a diverse set of modules. In that company if you want to provide module internals you provide it via a java interface, that hides the actual implementing type and gives an interface for the requesting module. Now I want to have one provider to be able to provide data for multiple modules that expose different fields or methods of the actual internal data.

Therefore I have an internal Object, which has some data and I have an interface for each module that needs access to some but not strictly all fields. Finally I have an external object that implements all those interfaces and holds an instance of the internal object to delegate the method calls:

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(); }
}

Now that is all fine and dandy, but if I want to provide - lets say - repository methods for finding a list of said objects typed for the correct module, I run into problems with how I can achieve that. I would wish for something like the following:

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

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

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

This doesn't compile saying the return type is incompatible.So my question is, if it is possible to achieve something like that and if, how?


I should note that I tried some different approaches which I want to include for completeness and to portray their downsides (in my eyes).

Approach 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() {
        // ...
    }
}

This approach is quite close to the solution I would prefer, but results in code like this:

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

Therefore requiring the user to include the "? extends" into each List-Declaration regarding to an invocation of loadAllObjects().

Approach 2:

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

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

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

This approach just omits the generic in the ExternalObjectRepository and therefore reduces the type safety too much in my opinion. Also I haven't tested if this actually works.


Just to reharse, is there any possible way to define the loadAllObjects-method in a way that enables users to get lists that are typed with the objects for their respective module without

  • requiring "? extends" in the users code
  • degrading type safety in the repository implementation
  • using class/interface level generics

解决方案

The challenge with allowing it to be typed as List<ModuleXObject> is that other code may hold is as a List<ExternalObject>.

All ExternalObject instances are ModuleXObject instances but the inverse is not true.

Consider the following additional class:

public class MonkeyWrench implements ModuleXObject{
    //STUFF
}

MonkeyWrench instances are NOT ExternalObject instances but if one could cast a List<ExternalObject> to a List<ModuleXObject> one could add MonkeyWrench instances to this collection, and this causes a risk of run time class cast exceptions and ruins type safety.

Other code could very easily have:

for(ExternalObject externalObject:externalObjectRepository.loadAllObjects())

If one of those instances is a MonkeyWrench instance, run time class cast, which is what generics are meant to avoid.

The implication of ? extends ModuleXObject is that you can read any object from the collection as a ModuleXObject but you can't add anything to the collection as other code may have additional constraints on the collection that are not obvious/available at compile time.

I'd suggest in your case to use ? extends ModuleXObject as its semantics seem to align with what you want, namely pulling out ModuleXObject instances, e.g.

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

这篇关于List中的Java泛型返回从多个接口继承的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-27 13:39