我有一个使用存储实体类型参数化的存储库接口。在其中的其他方法中,我感兴趣的有两个:实例化实体的create()方法和保存该实体的save()方法:

public interface INamedEntityRepository<T extends INamedEntity> {
    T create(String name);
    void save(T namedEntity);
}
...


接下来是如何使用此接口的代码段。我收到一个编译错误,说从create()返回的类型与传递到save()的类型不兼容。

INamedEntityRepository<? extends INamedEntity> repo = getEntityRepository();

INamedEntity toSave = repo.create("Named");
... // configure the entity more...
repo.save(toSave);
      ^


The method save(capture#7-of ? extends INamedEntity) in the type INamedEntityRepository<capture#7-of ? extends INamedEntity> is not applicable for the arguments (INamedEntity)。我能理解这一点,因为实际上INamedEntity不一定是预期的类型。

但是即使这样做

repo.save(repo.create("Named")));


不会帮助:

The method save(capture#7-of ? extends INamedEntity) in the type INamedEntityRepository<capture#7-of ? extends INamedEntity> is not applicable for the arguments (capture#8-of ? extends INamedEntity)

有什么问题?如何正确处理这种情况?
提前致谢。

最佳答案

无论是否将repo.create("Named")的结果存储在变量中,编译器都会检查其类型,并且由于create返回的类型为INamedEntity,因此将无法正常工作。要解决此问题,编译器必须知道create返回的内容是save可以接受的子类型,而这恰恰是您不使用通配符的时候。

在这种特殊情况下,您当然知道类型是正确的,因此可以使用如下所示的不安全类型转换:

((INamedEntityRepository<INamedEntity>) repo).save(repo.create("Named"));


或者您可以将不安全操作的问题委托给其他位置,例如声明repo首先不使用通配符。



如果getEntityRepository()实际上返回某种具体类型,而不是通配符类型,则可以使用如下代码:

void <T extends INamedEntity> test() {
    INamedEntityRepository<T> repo = getEntityRepository();
    T toSave = repo.create("Named");
    repo.save(toSave);
}


现在我把它打出来看起来很明显...

10-07 13:48