在Java 8中更改了类型推断。现在,对于构造函数和方法,类型推断同时查看目标类型和参数类型。 考虑以下:
interface Iface {}
class Impl implements Iface {}
class Impl2 extends Impl {}
class Acceptor {
public Acceptor(T obj) {}
}
T foo(T a) { return a; }
以下现在在Java 8中可以正常(但在Java 7中没有):
Acceptor a = new Acceptor<>(new Impl2());
// Java 8 cleverly infers Acceptor
// While Java 7 infers Acceptor (causing an error)
当然,这在以下两个方面都给出了错误:
Acceptor a = new Acceptor(new Impl2());
这在Java 8中也可以:
Acceptor a = foo (new Acceptor<>(new Impl2()));
// Java 8 infers Acceptor even in this case
// While Java 7, again, infers Acceptor
// and gives: incompatible types: Acceptor cannot be converted to Acceptor
以下两者都给出了错误,但错误不同:
Acceptor a = foo (new Acceptor(new Impl2()));
// Java 7:
// incompatible types: Acceptor cannot be converted to Acceptor
// Java 8:
// incompatible types: inferred type does not conform to upper bound(s)
// inferred: Acceptor
// upper bound(s): Acceptor,java.lang.Object
显然,Java 8使类型推理系统更加智能化。 这会导致不兼容吗? 一般来说,没有。 由于类型擦除,只要程序编译,实际上并不重要的是推断出什么类型。 Java 8是否编译所有Java 7程序? 它应该,但你提出了一个案例,但它没有。
似乎正在发生的事情是Java 8没有很好地处理通配符。 它似乎将它们视为一种它无法满足的限制性约束,而不是将它们视为缺乏约束。 我不确定它是否跟随JLS的信件,但我至少在精神上称这是一个bug。
仅供参考,这确实有效(请注意,我的Acceptor没有您的类型限制):
Acceptor> a = new Acceptor<>(new Impl2());
请注意,您的示例在方法参数之外使用通配符类型(这是不可取的),我想知道在方法调用中使用菱形运算符的更典型代码中是否会出现相同的问题。 (大概。)