我有一个使用存储实体类型参数化的存储库接口。在其中的其他方法中,我感兴趣的有两个:实例化实体的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);
}
现在我把它打出来看起来很明显...