以下示例在Java 7中成功编译,无法在Java 8(及更新版本)中编译。
public abstract class Example<T>
{
public T method()
{
return method(new HashMap());
}
abstract T method(Map<String, String> arg);
}
Java 7:
BUILD SUCCESSFUL in 1s
Java 8:
> Task :compileJava FAILED
C:\dev\projects\Java8\src\main\java\example\Example.java:10: error: incompatible types: Object cannot be converted to T
return method(new HashMap());
^
where T is a type-variable:
T extends Object declared in class Example
上述错误表示method(new HashMap())
返回Object
而非预期T
。
为避免Java 8中出现此错误,我必须提供泛型类型参数,即将new HashMap()
更改为new HashMap<>()
。
令人不安的是,传递给method(Map<String, String>)
的原始类型参数引起的错误实际上是关于此方法返回Object
而不是T
。所以我可以期待:
T result = method(new HashMap<>());
......,但是:
Object result = method(new HashMap());
如果提供非泛型类型参数,并且预期泛型类型参数,则突然忘记参数化类型的方法返回似乎是直观的行为。它只是方法定义中参数的上下文,我希望在相同的方法中与返回类型的上下文隔离开来。定义
这种行为是否有正当理由和适用的解释?我知道在Java 8中影响泛型的变化,但没有与这个特定情况相匹配。
感谢您的回答。
答案 0 :(得分:2)
15.12.2.6。方法结果和引发类型
所选方法的结果类型确定如下:
[...]如果方法需要未经检查的转换 适用时,结果类型是方法的擦除(§4.6) 声明的返回类型。 [...]
它在JDK-6791481中被提升。
如果我要public abstract class Example<T extends java.lang.Exception>
,那么我会得到error: incompatible types: Exception cannot be converted to T
。
(似乎我似乎无法找到一天的答案,详细解释一个长问题,发布并在不久之后找到答案。)
答案 1 :(得分:1)
我无法真正找到java-7的问题(我会尝试更多),但似乎通过以下方式指定in the JLS:
未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.4节,第9.4节)或非静态字段(第8.3节)M的类型是原始的在与C对应的泛型声明中对应于其类型擦除的类型。
我认为就是这个,因为我在原始类型下找不到更能解释它的东西。或者,简单来说,一旦你使用原始类型,其他一切(甚至是不相关的东西)也将使用擦除类型。