以下程序在Java7和Eclipse Mars RC2中编译Java8:
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);
}
}
}
我知道类型推断在Java8中发生了很大变化(例如,由于JEP 101“广义目标类型推断”)。那么,这是一个错误还是一个新的语言“功能”?
编辑:我也向Oracle报告了JI-9021550,但以防万一这是Java8中的一个“功能”,我也向Eclipse报告了这个问题:
由于bayou.io的回答,我们可以把问题缩小到
<X extends List<?>> void a(X instance) {
b(instance); // error
}
static final <T> List<T> b(List<T> list) {
return list;
}
产生错误,同时
<X extends List<?>> void a(X instance) {
List<?> instance2=instance;
b(instance2);
}
static final <T> List<T> b(List<T> list) {
return list;
}
可以编译没有问题。instance2=实例
的赋值是一个扩展的转换,这也应该发生在方法调用参数上。所以这个答案模式的不同之处在于附加的子类型关系。
请注意,虽然我不确定这种特定情况是否符合Java语言规范,但一些测试显示,Eclipse接受代码可能是因为它在一般通用类型方面更加草率,如下所示,绝对不正确,代码可以编译没有任何错误或警告:
public static void main(String... arg) {
List<Integer> l1=Arrays.asList(0, 1, 2);
List<String> l2=Arrays.asList("0", "1", "2");
a(Arrays.asList(l1, l2));
}
static final void a(List<? extends List<?>> type) {
test(type);
}
static final <Y,L extends List<Y>> void test(List<L> type) {
L l1=type.get(0), l2=type.get(1);
l2.set(0, l1.get(0));
}
感谢你的错误报告,也感谢霍尔格在你的回答中给出的例子。这些和其他几个问题最终让我对11年前Eclipse编译器中的一个小改动产生了疑问。重点是:Eclipse非法扩展了捕获算法,以递归方式应用于通配符边界。
有一个例子表明,这种非法更改使Eclipse行为与javac完全一致。几代Eclipse开发人员对这个老决定的信任超过了我们在JLS中可以清楚看到的。今天,我相信之前的偏差一定有不同的原因。
今天,我鼓起勇气在这方面将ecj与JLS对齐,瞧,5个看起来极其难以破解的错误,基本上就这样得到了解决(加上一点调整作为补偿)。
因此:是的,Eclipse有一个bug,但是这个bug在4.7里程碑2中已经被修复了:)
以下是ecj今后将报告的内容:
The method b(List<T>) in the type Test is not applicable for the arguments (capture#1-of ? extends List<?>)
捕获绑定中的通配符找不到检测兼容性的规则。更准确地说,在推理过程中(精确地说是合并),我们会遇到以下约束(T#0表示推理变量):
⟨T#0 = ?⟩
天真地说,我们可以将类型变量解析为通配符,但是——可能是因为通配符不被视为类型——缩减规则将上述定义为缩减为FALSE,从而导致推理失败。
免责声明——我对这个主题了解不够,下面是我的一个非正式推理,试图证明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>
本质上,这是无法解决的。例如,如果X=List,则不存在
T
不确定Java7如何推断这种情况。但是javac8(和IntelliJ)的行为是合理的。
现在,这个变通方法是如何工作的?
List<?> instance = type.newInstance();
b(instance); // ok!
它之所以能工作,是因为通配符捕获引入了更多类型信息,“缩小”了
实例的类型
instance is List<?> => exist W, where instance is List<W> => T=W
不幸的是,当
实例
为X
时,这并没有完成,因此需要处理的类型信息较少。
可以想象,该语言也可以“改进”为X进行通配符捕获:
instance is X, X is List<?> => exist W, where instance is List<W>
错误:(65,52)java:不兼容类型:推理变量U的边界不兼容等式约束:akka。http。javadsl。模型HttpResponse下限:com。我的演员。聊天演员。聊天信息 下面这行代码显示了错误: 这里是HttpResponse是Akka Http的。 我不知道它在说什么。解决它的方法应该是什么?
JDK 1.8 设置和收集。 我想数一数那个十字路口 我试试这个: 但我有一个错误:
我有以下代码 出于某种原因,它抛出了以下编译错误 Solution.java:11:错误:不兼容类型:推断变量T具有不兼容的边界List=Arrays.asList(A);^相等约束:整数下界:int[]其中T是类型变量:T扩展方法中声明的Object asList(T...) 我假设这是一个Java8功能但我不知道如何解决这个错误
我有一个树对象,它包含树对象的子对象(HashMap),等等 我需要按numericPosition变量筛选对象 例如: 在这种情况下,我应该得到一个树对象过滤的数字位置 树类 以防 我得到这个错误:错误:不兼容类型:推断变量R具有不兼容的边界 我一直在遵循这个例子,但它对我不起作用。https://www.mkyong.com/java8/java-8-filter-a-map-examples
正如斯图尔特·马克斯(Stuart Marks)指出的那样,我试图为这里所述的问题编写一个解决方案,以使用一个helper类。由于这个错误,我被代码卡住了: 我当前的代码: 我本人对Java 8很陌生,解决方案可能是错误的,但我不知道错误是什么意思,也不知道如何解决它。元组类过去也是泛型的,但因为我认为这导致了问题,我删除了泛型类型,但仍然存在相同的错误。
我已经复习了“可能相关”的问题,但它们似乎没有帮助;我也是一个初学者,尤其是Java8,所以请耐心听我说! 问题是,我想将一个包含值列表的文件(在本例中是双数字)读入一个数组。我在助手类中作为方法来做这些,因为我希望在我的项目中需要多次这样做。 我已经创建了一个将文件转换为二维双数组的简单方法- 这很有效,我一直在成功地使用它。然后我想尝试将一个包含一长串大数字的文件读入一个1D数组,所以尝试快速