调用javagenerics方法

给出通用方法:

 List getGenericList(int i) {...} 

以下代码编译时没有任何警告:

 public List getStringList(boolean b){ if(b) return getGenericList(0); else return getGenericList(1); } 

但是这个会生成’Type mismatch’编译错误:

 public List getStringList(boolean b) { return (b) ? getGenericList(0) : getGenericList(1); } 

为什么?

不是generics问题 ,而是编译器必须推断三元表达式类型的结果。

这个等效代码也是如此。 此代码有效:

 public byte function(boolean b){ if(b) return 1; else return 2; } 

虽然这不是:

 public byte function(boolean b) { return (b) ? 1 : 2; } 

原因是编译器尝试推断此表达式的类型时

  return (b) ? 1 : 2; 

它首先必须获得每个操作数的类型,并检查它们是否兼容( 参考 )以评估三元表达式是否有效。 如果传播“返回”的类型以自动转换或提升每个操作数,则可能导致根据此表达式的上下文以不同方式解析三元表达式的类型。

鉴于“返回”的类型不能传播到操作数,那么在所提到的情况下:

  return (b) ? getGenericList(0) : getGenericList(1); 

无法完成generics类型的绑定 ,因此每个操作数的类型都解析为List 。 然后编译器断定整个表达式的类型是List ,它不能自动转换为List (因为它们不是兼容的类型)。

而另一个

  return getGenericList(0); 

它应用“return”的类型来绑定generics类型T,因此编译器断定该表达式具有List类型,可以安全返回。

这是因为generics类型推导的边缘情况

在显式返回中,每个getGenericList的返回类型可以简单地设置为List(向外信息向内传播)

但在有条件的情况下它走向另一种方式它的类型是两种可能性中更一般的(向内信息向外传播)

编译器可以在这里隐式地扣除信息但是如果你确实需要的话,它还没有构建错误报告

当评估三元运算符时,它的结果不受任何类型的约束。 这就像你打电话:

 getGenericList(0); 

尝试编译上面的内容,编译将失败。

在return语句中,结果绑定到函数的返回类型并进行求值。

编辑:

我错了。 上面的语句编译,但结果类型计算为(List )。 尝试编译:

 List l = (List)getGenericList(0); 

这个会失败。

这是因为javac需要推断T ,但T不会出现在参数类型中。

 static T foo(){ .. } foo(); // T=? 

仅在2种情况下,javac可以从上下文中推断出T

 String s = foo(); // #1: assignment String bar(){ return foo(); // #2: return 

在其他情况下,javac不会,而T只是简称为Object

但是这种方法无论如何都是危险的。 你的方法怎么知道它是时候返回List ,而不是其他东西的列表? 没有关于T信息。

看起来它只是低效的编译。

正如Maurice所说,通常,编译器通过函数参数确定T的类型。 在这种情况下,没有任何。

但是,因为getStringList()返回List并且它调用return getGenericList() ,所以编译器足够聪明,可以将getStringList的返回类型转发到getGenericList,并以这种方式确定类型。

我的猜测是,在三元运算符中,它不会反向绑定,而是在每个子语句中找到公分母并将其指定为三元语句的输出,并且编译器不够智能以传递预期输出将三元陈述纳入其子语句中。

注意,你可以直接将type参数传递给函数调用,它工作正常,即:

 return b ? this. getGenericList(0) : this. getGenericList(1); 

编译得当。