我有一个使用存储实体类型参数化的存储库接口。在其中的其他方法中,我有两个感兴趣:实例化实体的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)
。
有什么问题?如何正确处理这种情况? 提前谢谢。
答案 0 :(得分:1)
您将无法在使用捕获通用定义(即?extends)声明的任何INamedEntityRepository实例上调用.save。这与您无法在列表上调用add的方式类似。
答案 1 :(得分:1)
问题是编译器不知道未知类型是两种用法的相同未知类型。解决方案是将类型“锁定”为两种用法的特定类型。例如,如果这是一种方法,您可以键入方法:
public <T extends INamedEntity> void someMethod(String name) {
INamedEntityRepository<T> repo = getEntityRepository(); // may need cast here
T toSave = repo.create(name);
// do stuff with toSave
repo.save(toSave);
}
您尚未显示getEntityRepository()的签名,因此可能需要强制转换,因此如果它也是类型化方法,则可以使用以下语法:
INamedEntityRepository<T> repo = MyClass.<T>getEntityRepository();
如果是静态,或
INamedEntityRepository<T> repo = this.<T>getEntityRepository();
如果是非静态的,则通过该类型传递。
答案 2 :(得分:0)
无论是否将repo.create("Named")
的结果存储在变量中,编译器都会检查其类型,并且由于create
返回的类型为INamedEntity
,因此赢了&#39工作。要解决此问题,编译器必须知道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);
}
现在看起来非常明显我输入了...
答案 3 :(得分:0)
Silly Freak和Bohemian的解锁方法确实给了我一个警告,让我在做getEntityRepository()
时做一个演员。所以我在这里放了一个变种,它为我编译而没有任何警告:
protected abstract INamedEntityRepository<? extends INamedEntity> getEntityRepository();
...
// the method that extracts the code of interest
private <T extends INamedEntity> void test(String name, INamedEntityRepository<T> repo) {
T toSave = repo.create(name);
repo.save(toSave);
}
...
test("Named", getEntityRepository());