为什么Java编译器不允许我返回泛型类型?

时间:2017-04-10 13:57:16

标签: java generics

我对泛型有点不知所措。我有以下代码:

malloc

当我尝试这个时,IntelliJ(即编译器)告诉我public interface SampleValue<T> { T getValue(); } public static class SampleBoolean implements SampleValue<Boolean> { @Override public Boolean getValue() { return Boolean.TRUE; } } public static final class SampleValueGenerator { private SampleValueGenerator() { // do not call } public static <T, R extends SampleValue<T>> R forType(Class<T> clazz) { if(Boolean.class.equals(clazz)) { return new SampleBoolean(); } } } R是不兼容的类型(对于SampleBoolean行)。

当我尝试非泛型(原始)返回类型

return

我没有得到任何错误;

public static <T> SampleValue forType(Class<T> clazz) {

(使用public static <T, R extends SampleValue<?>> R forType(Class<T> clazz) {通配符)但是再次失败。而对于

?

我得到public static <T> SampleValue<T> forType(Class<T> clazz) {

我的猜测是它与例如列表不是列表的祖先(但是兄弟姐妹),但我没有看到上面的树木。

有人可以解释一下发生了什么,为什么长长的例子不起作用?

更新:NB:我的想法是为不同的类型添加一些if / else分支,但是当编译器开始抱怨时我停止了...

3 个答案:

答案 0 :(得分:2)

原因是你的条件并没有向编译器证明什么。

您在这里遇到的困惑涉及您的条件:

if(Boolean.class.equals(clazz))

通过此检查,您可以推断TBoolean,但编译器无法强制执行此操作。编译器没有隐含地假设此检查将确保TBoolean。 (所有编译器都知道此方法的上下文中的equals是它返回boolean。)

因此,尽管您进行了检查,但RSampleBoolean是不兼容的类型,因为R extends SampleValue<T>T可以是任何类型。

我无法确定基于new SampleValue<T>确保T返回的方法,但如果我这样做,我将使用解决方案编辑此答案。我很乐意看到别人的想法。

答案 1 :(得分:1)

我认为问题在于SampleBoolean实现SampleValue<Boolean>这是一种特定的类型而不是通用的。另一方面,R被声明为扩展泛型类型SampleValue<T>

SampleValue<T>SampleValue<Boolean>是两种不同的类型,因此这就是您收到编译错误的原因。 forType函数想要返回泛型类型R,并使用以下语句返回特定类型:

return new SampleBoolean();

答案 2 :(得分:0)

您要返回的R始终是实现Boolean的SampleValue的R而不是实现T的SampleValue的R(在运行时设置的泛型类型)。

// if i do this
SampleValueGenerator.forType(Integer.class) 
// i am expecting something that implements SampleValue<Integer>
// but you are always returning something that implements SampleValue<Boolean>

编辑这应该有效(尚未测试)

public static <T, R extends SampleValue<T>> R forType(Class<T> clazz) {
    return () -> {
        try{
            return (T)clazz.newInstance(); // Also clazz should have a default constructor.
        }catch(Excepetion e){
            // This catch block should be for NoSuchMethodException and InstantionException
        }
    }
}