Java 8 自动装箱 + 泛型:变量与方法的不同行为
我发现一段代码在从Java 7切换到Java 8后停止编译。它没有提供任何新的Java 8的东西,如lambda或stream。
我将有问题的代码缩小到以下情况:
GenericData<Double> g = new GenericData<>(1d);
Double d = g == null ? 0 : g.getData(); // type error!!!
您可能猜到 的构造函数有一个该泛型类型的参数,并且该方法仅返回该泛型类型。(有关完整的源代码,请参见下文。GenericData
getData()
现在困扰我的是,在Java 7中,代码编译得很好,而在Java 8中,我得到以下错误:
CompileMe.java:20: error: incompatible types: bad type in conditional expression
Double d = g == null ? 0 : g.getData();
^
int cannot be converted to Double
Java 7似乎能够完成从int ->double ->Double的过渡,但Java 8试图立即从int ->Double失败。
我发现特别有趣的是,当我将代码从 更改为 时,Java 8 确实会接受代码,即通过变量本身而不是 getter-method 访问 的值:getData()
data
GenericData
Double d2 = g == null ? 0 : g.data; // now why does this work...
所以我在这里有两个问题是:
- 为什么 Java 8 不推断出像 Java 7 这样的类型,并在自动装箱双倍之前将我的 int 转换为双倍?
- 为什么这个问题只发生在泛型方法上,而不发生在泛型变量上?
完整的源代码:
public class CompileMe {
public void foo() {
GenericData<Double> g = new GenericData(1d);
Double d = g == null ? 0 : g.getData(); // type error!!!
Double d2 = g == null ? 0 : g.data; // now why does this work...
}
}
class GenericData<T> {
public T data;
public GenericData(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
要对其进行测试,请按如下方式运行编译器:
javac -source 1.7 -target 1.7 CompileMe.java # ok (just warnings)
javac -source 1.8 -target 1.8 CompileMe.java # error (as described above)
最后,如果情况很重要:我运行Windows 8和Java 1.8.0_112(64位)。