我有这种实体关系模型:
// Entity interface
public interface Entity<Reference extends Entity<Reference>> extends Iterable<Attribute<Reference, ?>> {
// set a referrer and the RelationMetadata to this Entity
<Referrer extends Entity<Referrer>> void setReferrer(RelationMetadata<Referrer, Reference> relationMetadata, Referrer referrer);
some other methods...
}
// Relation Metadata is a relation descriptor
public class RelationMetadata<Referrer extends Entity<Referrer>, Reference extends Entity<Reference>> {
some methods...
}
我想创建我的实体(&#39; selectedEntity&#39;)阅读其元数据,加载其引荐来源并将这些引用连接到“selectEntity&#39;”。所以我的用法是:
// obtain the entity metadata
EntityMetadata<E> entityMetadata = EntityManager.getEntityMetadata(selectedEntity.getClass());
// cycle on each relation my entity is reference
for (Iterator<RelationMetadata<? extends Entity<?>, E>> iterator = entityMetadata.getAsReferencesRelationsMetadataIterator(); iterator.hasNext();) {
// for each relation
RelationMetadata<? extends Entity<?>, E> relationMetadata = (RelationMetadata<? extends Entity<?>, E>) iterator.next();
// instance dao
Dao<?> referrerDao = DaoManager.getDao(relationMetadata.getReferrer());
some code..
// select referrer entity
Entity<?> referrer = referrerDao.selectByKey(...);
// set referrer to my 'selectedEntity'
selectedEntity.setReferrer(relationMetadata, referrer);
}
问题是我获得了这个编译错误调用方法&#39; setReferrer&#39;:
'The method setReferrer(RelationMetadata<Referrer,E>, Referrer) in the type Entity<E> is not applicable for the arguments (RelationMetadata<capture#16-of ? extends Entity<?>,E>, Entity<capture#18-of ?>)'
我知道&#39;推荐人&#39;我已加载正确连接到&#39; relationMetadata&#39;但我怎么能提示编译器?
这是一个非常烦人的问题,我不知道如何解决它。
谢谢 -G。
答案 0 :(得分:0)
问题是通配符。声明setReferrer
的方式你将无法使用这些通配符调用它。对于两个通配符,<Referrer>
类型参数的捕获方式不同。
RelationMetadata<? extends Entity<?>, E> relationMetadata;
Entity<?> referrer;
selectedEntity.setReferrer(relationMetadata, referrer);
编译器无法确定两个?
是同一类型。用两个不同的通配符调用setReferrer
是不安全的。
这是一个更简单的例子:
static <T> void merge(List<T> a, List<T> b) {}
<T>
断言a
和b
都具有相同的泛型类型参数。我可以这样称呼这个方法:
List<String> a = new ArrayList<String>();
List<String> b = new ArrayList<String>();
merge(a, b);
显然我不能这样称呼它:
List<String> a = new ArrayList<String>();
List<Double> b = new ArrayList<Double>();
merge(a, b);
但我也不能这样称呼它:
List<?> a = new ArrayList<String>();
List<?> b = new ArrayList<String>();
merge(a, b);
我不能这样做,因为没有办法告诉a
和b
具有相同的类型参数。 (除非是作为一个人并查看代码。)因此编译器捕获a
和b
的通配符彼此不同。
你的类型更复杂,但是你得到的错误也来自同一个问题。
我不知道该告诉你什么,除非你有太多的通配符。你需要想出办法去做你正在做的事情,而用它们就少了。您正在使用的实际类型参数需要传递更多,或者此例程需要成为参数化对象的一部分。
看到你的评论我想我会看到你在做什么,你可以在这里使用帮助方法。这在"Wildcard Capture and Helper Methods"。
中有所描述它的工作方式是:
RelationMetadata
时返回任何类型的next
,你有一个这样的辅助方法:
static <R extends Entity<R>, E extends Entity<E>> process(
RelationMetadata<R, E> relationMetadata,
Entity<E> selectedEntity
) {
// not sure what the Dao should be, I guessed
Dao<R> referrerDao = DaoManager.getDao(relationMetadata.getReferrer());
...
R referrer = referrerDao.selectByKey(...);
selectedEntity.setReferrer(relationMetadata, referrer);
}
理论上,做这样的事情可以捕获RelationalMetadata
的类型并一般地使用它。循环将被重构为这样的东西:
for(
Iterator<RelationMetadata<? extends Entity<?>, E>> iterator = (
entityMetadata.getAsReferencesRelationsMetadataIterator()
);
iterator.hasNext();
) {
process(iterator.next(), selectedEntity);
}
假设selectedEntity
已经在这种情况的上下文中进行了一般性的输入。 (我认为这将是一个Entity<E>
。)如果它是Entity<?>
或类似的东西会使事情变得复杂。
捕获帮助程序是执行此类操作的“正确”方法。