我最近开始使用Java,但在处理泛型类型时仍然感到困惑。以下是我遇到一些问题的简化方案。
我有一个类,它使用Class类型作为Key和该类对象的集合来保存Map:
public class GenericListInside {
private Map<Class<?>, List<?>> mapping = new HashMap<>();
public <T> void addListing(Class<T> clazz, List<T> object) {
mapping.put(clazz, object);
}
}
我可以毫无问题地调用addListing:
GenericListInside gli = new GenericListInside();
List<Foo> list = new ArrayList<>();
//add something to list
gli.addListing(Foo.class, list);
现在我决定创建一个Class来提供流畅的界面。类似的东西:
with(Foo.class).use(list);
然后我来了:
public class FluidInserter<T> {
Class<T> clazz;
GenericListInside gli = new GenericListInside();
public FluidInserter with (Class<T> clazz) {
this.clazz = clazz;
return this;
}
public <T> void use(List<T> list) {
gli.addListing(clazz, list);
}
}
但是当我尝试编译时,我得到:
错误:(18,12)java:类util.GenericListInside中的方法addListing不能应用于给定的类型;
required:java.lang.Class,java.util.List
发现:java.lang.Class,java.util.List
原因:推断类型不符合等式约束(s)
推断:T
等式约束:T,T
这条消息有点令人困惑......任何人都能弄清楚我做错了什么?
答案 0 :(得分:4)
流体构建器的泛型方法采用通用方法参数,但该参数与clazz
字段的类型不同,尽管名称重叠。
只需从方法声明中删除<T>
,同时将List<T>
作为参数:
public void use(List<T> list) {
gli.addListing(clazz, list);
}
偏离主题说明:您不希望在FluidInserter
方法中返回原始类型with
。将返回类型更改为:
public FluidInserter<T> with (Class<T> clazz)
答案 1 :(得分:3)
问题在于use(List<T> list)
方法的定义:
public <T> void use(List<T> list) {
gli.addListing(clazz, list);
}
在这里,您通过引入具有相同名称的方法范围的type-parameter,隐藏类范围的类型参数T
。
应该是:
public void use(List<T> list) {
gli.addListing(clazz, list);
}
它应该编译得很好,因为T
已经在类级别定义。
答案 2 :(得分:2)
您的问题是以下声明:
public <T> void use(List<T> list) {
gli.addListing(clazz, list);
}
由于您已经在类级别定义了通用<T>
,因此无需对该方法进行泛化。
我建议您将签名更改为以下内容:
public void use(List<? extends T> list) {
// same logic here
}
另外,作为旁注,我认为你也应该GenericListInside
通用。现在,mapping
字段的定义允许在键和值中混合类型,这是你不想要的。
修改强>
您可以像这样添加GenericListInside
的通用:
public class GenericListInside<T> {
private final Map<Class<T>, List<T> mapping = new HashMap<>();
public void addListing(Class<T> clazz, List<T> list) {
mapping.put(clazz, list);
}
}