我对泛型有点不知所措。我有以下代码:
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分支,但是当编译器开始抱怨时我停止了...
答案 0 :(得分:2)
原因是你的条件并没有向编译器证明什么。
您在这里遇到的困惑涉及您的条件:
if(Boolean.class.equals(clazz))
通过此检查,您可以推断T
是Boolean
,但编译器无法强制执行此操作。编译器没有隐含地假设此检查将确保T
为Boolean
。 (所有编译器都知道此方法的上下文中的equals
是它返回boolean
。)
因此,尽管您进行了检查,但R
和SampleBoolean
是不兼容的类型,因为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
}
}
}