从Java 7开始,菱形语法并不总是在方法参数中起作用,例如Why does the diamond operator not work for java.util.Collections methods in Java 7?。该问题的答案提到Java 8中的目标类型推断修复了这个问题。
是否还有其他无法使用钻石语法的情况?
答案 0 :(得分:20)
钻石操作符不能总是在Java 8中使用。改进Java 8(JEP 101)推理的最初计划有两个目标:
只实施了第一个。借用JEP中的示例,请考虑以下类:
class List<E> {
static <Z> List<Z> cons(Z head, List<Z> tail) { ... };
E head() { ... }
}
在Java 8中,改进的方法上下文推断允许以下编译。对于Java 7,它将失败并显示错误expected List<Integer>, found List<Object>
List<Integer> l = List.cons(42, new List<>());
但是,需要推断链式调用的示例仍然无法使用Java 8:
Integer i = new List<>().head();
JSR 335的D部分提供了一个关于为什么链接表达式推断被Java 8放弃的提示:
有一些兴趣允许在a()。b()中推断&#34; chain&#34;:,将类型信息从b的调用传递给a的调用。这为推理算法的复杂性增加了另一个维度,因为部分信息必须在两个方向上传递;只有当a()的返回类型的擦除对于所有实例化(例如List)都是固定的时,它才有效。此特征不适合多聚表达模型,因为目标类型不能轻易导出;但也许还有其他增强功能,可以在将来添加。
还有一些更人为的例子,其中不能使用钻石。
如果错误计数,则不会在jdk8u25之前使用javac进行编译。 (见JDK-8029002)
class Test {
class C<T extends C<T>> {}
void m() {
C<?> i = new C<>();
}
}
error: incompatible types: cannot infer type arguments for Test.C<>
C<?> i = new C<>();
^
reason: inferred type does not conform to upper bound(s)
inferred: Test.C<CAP#1>
upper bound(s): Test.C<Test.C<CAP#1>>,Test.C<CAP#1>
where CAP#1 is a fresh type-variable:
CAP#1 extends Test.C<CAP#1> from capture of ?
还有一个性能问题(JDK-8051946),新的类型推断实现可能会影响使用菱形运算符的代码。如果使用菱形运算符,则以下示例需要几分钟才能编译。
class Test {
<T> T and(T a, T b) { return null; }
class C<T> {}
void g(String s) {}
void g(Object s) {}
void m() {
g(
and(
and(
and(
and(
and(
and(
and(new C<>(),
new C<>()),
new C<>()),
new C<>()),
new C<>()),
new C<>()),
new C<>()),
new C<>()));
}
}