我的代码无法使用JDK 7编译,但成功使用JDK 8进行编译。
抽象实际代码:
interface A {
...
}
class B implements A {
...
}
public void AAA(List<A> list) {...}
AAA(Collections.singletonList(new B()));
Collections.singletonList定义为
public static <T> List<T> singletonList(T o) {
return new SingletonList<>(o);
}
据我所知,基于泛型,T将被推断为B,因此Collections.singletonList(new B())将是List,由于Java泛型不变,因此无法分配给List。
但是使用JDK 8,T被推断为A并且编译成功。
我想知道如何将T推断为A,因为这里有两个变量类型为T:A和B.
是否有优先顺序?或者编译器是否找到共同的祖先类?
更感谢附加官方文件!
提前致谢!
PS1。 JDK 7的版本是Oracle 1.7.0_79,JDK 8的版本是Oracle 1.8.0_66。
PS2。这是实际代码的链接:
答案 0 :(得分:5)
嗯,在语言规范中有一个全新的章节§18. Type Inference,但这并不容易阅读。即使是第一部分的摘要,也很难解决你的问题,但很难:
与Java®语言规范的Java SE 7版相比,对推理的重要更改包括:
- 添加对lambda表达式和方法引用的支持,作为方法调用参数。
- 概括以多边形表达式定义推理,在推理完成之前,它可能没有明确定义的类型。这具有改进嵌套泛型方法和菱形构造函数调用的推断的显着效果。
- 描述如何使用推理来处理通配符参数化的功能接口目标类型和最具体的方法分析。
- 澄清调用适用性测试(仅涉及调用参数)和调用类型推断(包含目标类型)之间的区别。
- 延迟解析所有推理变量,甚至是那些具有下限的变量,直到调用类型推断,以便获得更好的结果。
- 改善相互依赖(或自立)变量的推理行为。
- 消除错误和潜在的混淆源。该修订更仔细和精确地处理特定转换上下文和子类型之间的区别,并通过并行相应的非推理关系来描述减少。如果故意偏离非推理关系,则明确指出这些关系。
- 为未来发展奠定基础:推理的增强或新应用将更容易整合到规范中。
第二个项目符号对您的代码示例影响最大。您有一个泛型方法的嵌套方法调用,而没有指定显式类型参数,这使得它成为一个所谓的多表达式,其实际类型可能是从目标类型推断出来的,在您的情况下,这是AAA
的参数类型。
所以这是一个相当容易的星座,因为AAA
不是通用的,并且没有关于它的参数类型的歧义。它总是List<A>
。这里没有搜索“共同的祖先类”,所有必须检查的是,参数表达式的类型(B
)是否与推断类型(A
)兼容。
答案 1 :(得分:4)
最后在目标类型的最后解释了here。
目标类型已扩展为包含方法参数...
这意味着什么
AAA(Collections.singletonList(new B())); // returns List<A> NOT List<B>
在jdk-7方法中,不用于查找目标类型,这就是T被推断为B的原因,这就是失败的原因。
答案 2 :(得分:0)
目标类型&#34; http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
的部分它说
Java SE 8中不再需要这个。目标类型的概念已经扩展为包含方法参数,例如方法processStringList的参数。
你的方法AAA需要类型A的列表,所以我相信只要你为调用AAA()提供的类型是可用的类型转换或A的子类型,Java8的目标类型就会获得A over B基于您在代码中提供的提示?