Java泛型类型解析

时间:2016-02-10 14:51:47

标签: java generics

我最近开始使用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

这条消息有点令人困惑......任何人都能弄清楚我做错了什么?

3 个答案:

答案 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);
    }
}