以下程序在 Java 7 和 Eclipse Mars RC2 for Java 8 中编译:
import java.util.List;
public class Test {
static final void a(Class<? extends List<?>> type) {
b(newList(type));
}
static final <T> List<T> b(List<T> list) {
return list;
}
static final <L extends List<?>> L newList(Class<L> type) {
try {
return type.newInstance();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
使用javac 1.8.0_45编译,报如下编译错误:
Test.java:6: error: method b in class Test cannot be applied to given types;
b(newList(type));
^
required: List<T>
found: CAP#1
reason: inference variable L has incompatible bounds
equality constraints: CAP#2
upper bounds: List<CAP#3>,List<?>
where T,L are type-variables:
T extends Object declared in method <T>b(List<T>)
L extends List<?> declared in method <L>newList(Class<L>)
where CAP#1,CAP#2,CAP#3 are fresh type-variables:
CAP#1 extends List<?> from capture of ? extends List<?>
CAP#2 extends List<?> from capture of ? extends List<?>
CAP#3 extends Object from capture of ?
一种解决方法是在本地分配一个变量:
import java.util.List;
public class Test {
static final void a(Class<? extends List<?>> type) {
// Workaround here
List<?> variable = newList(type);
b(variable);
}
static final <T> List<T> b(List<T> list) {
return list;
}
static final <L extends List<?>> L newList(Class<L> type) {
try {
return type.newInstance();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
我知道类型推断在 Java 8 (e.g. due to JEP 101 "generalized target-type inference") 中发生了很大变化。那么,这是一个错误还是一个新的语言“功能”?
编辑:我也已将此问题作为 JI-9021550 报告给 Oracle,但以防万一这是 Java 8 中的“功能”,我也已向 Eclipse 报告了该问题:
最佳答案
免责声明 - 我对这个主题知之甚少,以下是我的非正式推理,试图证明 javac 的行为是正当的。
我们可以将问题简化为
<X extends List<?>> void a(Class<X> type) throws Exception
{
X instance = type.newInstance();
b(instance); // error
}
<T> List<T> b(List<T> list) { ... }
推断 T
, 我们有约束
X <: List<?>
X <: List<T>
本质上,这是无法解决的。例如,没有 T
如果 X=List<?>
则存在.
不确定 Java7 如何推断这种情况。但我会说,javac8(和 IntelliJ)表现得“合理”。
现在,这个解决方法是如何工作的?
List<?> instance = type.newInstance();
b(instance); // ok!
由于通配符捕获而起作用,它引入了更多类型信息,“缩小”了 instance
的类型
instance is List<?> => exist W, where instance is List<W> => T=W
不幸的是,当 instance
是 X
,因此可以使用的类型信息较少。
可以想象,该语言也可以“改进”以对 X 进行通配符捕获:
instance is X, X is List<?> => exist W, where instance is List<W>
关于java - 推理变量具有不兼容的界限。 Java 8 编译器回归?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30622759/