Java泛型:不兼容的通配符捕获

Java泛型:不兼容的通配符捕获,java,generics,bounded-wildcard,Java,Generics,Bounded Wildcard,我有一个用存储实体类型参数化的存储库接口。在其中的其他方法中,我有两个感兴趣的方法:实例化实体的create()方法和保存实体的save()方法: public interface INamedEntityRepository<T extends INamedEntity> { T create(String name); void save(T namedEntity); } ... INamedEntityRepository类型中的方法save(capture

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

public interface INamedEntityRepository<T extends INamedEntity> {
    T create(String name);
    void save(T namedEntity);
}
...
INamedEntityRepository类型中的方法save(capture#7-of?扩展INamedEntity)不适用于参数(INamedEntity)
。我可以理解这一点,因为实际上,
INamedEntity
不一定是预期的类型

但即使这样做

repo.save(repo.create("Named")));
不会有帮助的:

INamedEntityRepository类型中的方法save(capture#7-of?Extended INamedEntity)不适用于参数(capture#8-of?Extended INamedEntity)

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

您将无法调用。保存使用捕获泛型定义(即扩展)声明的任何INamedEntityRepository实例。这类似于不能在列表中调用add


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

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

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

这看起来很明显,现在我把它打出来了…

问题是编译器不知道未知类型对于两种用法都是相同的未知类型。解决方案是将该类型“锁定”为两种用法的特定类型。例如,如果这是一个方法,则可以键入该方法:

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);
}
公共方法(字符串名称){
INamedEntityRepository repo=getEntityRepository();//此处可能需要强制转换
T toSave=repo.create(名称);
//做些有助于节约的事情
回购保存(toSave);
}
您尚未显示getEntityRepository()的签名,因此可能需要强制转换,因此如果它也是类型化方法,则可以使用以下语法:

INamedEntityRepository<T> repo = MyClass.<T>getEntityRepository();
INamedEntityRepository repo=MyClass.getEntityRepository();
如果是静态的,或者

INamedEntityRepository<T> repo = this.<T>getEntityRepository();
INamedEntityRepository repo=this.getEntityRepository();

如果是非静态的,则传递类型。

愚蠢的怪胎和波西米亚解决方案使用类型锁定方法确实给了我一个警告,并让我在执行
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());
受保护的摘要在医学报告中
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());