使用java 8中的泛型类型错误,而不是java 7 [英] Type error using generics under java 8, but not java 7
问题描述
import java.util.Iterator;
class ASTNode< T extends ASTNode>实现Iterable< T> {
@Override public Iterator< T> iterator(){return null; }
}
类列表< T extends ASTNode>扩展ASTNode< T> {}
接口函数< F,T> {}
class Iterables {
public static< F,T>可迭代< T> transform(
Iterable< F> fromIterable,Function<?super F,?extends T> function){return null; }
}
class AstFunctions {
public static< T extends ASTNode<?>>功能< T,String> prettyPrint(){return null; }
}
public class Main {
public static void test(){
List<?扩展ASTNode<?>> list = null;
Iterables.transform(list,AstFunctions.prettyPrint());
}
}
证人:
$ javac -version
javac 1.8.0_05
$ javac -source 1.7 Main.java
warning:选项] bootstrap类路径未与-source连接1.7
1警告
$ javac -source 1.8 Main.java
Main.java:23:错误:方法转换类Iterable不能应用于给定类型;
Iterables.transform(list,AstFunctions.prettyPrint());
^
required:Iterable< F>,Function<?超级F扩展T#1>
found:List< CAP#1>,Function< ASTNode<?>,String>
原因:不能推断类型变量F,T#1,T#2
(参数不匹配;函数< CAP#1,String>不能转换为Function<?super CAP# ,?扩展String>)
其中F,T#1,T#2是类型变量:
F扩展方法< F,T#1>变换(Iterable&函数<?super F,?扩展T#1>)
T#1扩展在方法< F,T#1>变换(Iterable,Function<?super F,?extends T# 1>)
T#2扩展ASTNode<?>在方法< T#2>中宣称prettyPrint()
其中CAP#1是新的类型变量:
CAP#1扩展ASTNode<?>从捕获?扩展ASTNode<?>
1错误
(或许值得注意的是,配置为1.8兼容性的Eclipse没有问题这个代码)。
这是一个编译器错误吗?如果没有,那么假设我被允许更改 AstFunctions
和 Main
(但不是 ASTNode
,列表
,功能
或 Iterables
),我该如何编译这段代码?我也想了解,如果可能的话,Java 8的类型系统会发生什么变化,使得这段代码不能编译。
更新:看另一个答案 - 这是一个已经修复的javac中的错误。
不编译Java 8正在展现正确的行为:
-
Iterables.transform
期望Iterable< F> fromIterable
和Function<?超级F ...
,所以第一个通用类型的Function
需要是一个超级类的通用类型的你的主要是
- ,Iterable的类型是
F1 ==?扩展ASTNode<?>
,并且prettyPrint
返回的函数的第一个类型是F2 == T extends ASTNode< ?>
我不认为有办法证明F2是一个超类型F1。例如,假设你有:
class A1 extends ASTNode< A1> {}
class A2 extends ASTNode< A2> {}
在您的主要内容中:
列表与LT ;?扩展ASTNode<?>> list = new List< A1>(); // F1 = A1
你可以想象, prettyPrint
返回一个函数< A2,String>
(即 F2 = A2
),A2不是超类A1。
所以我相信编译错误是有道理的。但是,我不会根据规格来尝试证明这一点,因为这将大部分时间用于我们!
I have a piece of code which compiles fine under java 7, but not under java 8. Here is a self-contained reproducing example (I've taken real code that exhibits this problem and stubbed out all the implementations):
import java.util.Iterator;
class ASTNode<T extends ASTNode> implements Iterable<T> {
@Override public Iterator<T> iterator() { return null; }
}
class List<T extends ASTNode> extends ASTNode<T> {}
interface Function<F, T> {}
class Iterables {
public static <F,T> Iterable<T> transform(
Iterable<F> fromIterable, Function<? super F, ? extends T> function) { return null; }
}
class AstFunctions {
public static <T extends ASTNode<?>> Function<T, String> prettyPrint() { return null; }
}
public class Main {
public static void test() {
List<? extends ASTNode<?>> list = null;
Iterables.transform(list, AstFunctions.prettyPrint());
}
}
Witness:
$ javac -version
javac 1.8.0_05
$ javac -source 1.7 Main.java
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning
$ javac -source 1.8 Main.java
Main.java:23: error: method transform in class Iterables cannot be applied to given types;
Iterables.transform(list, AstFunctions.prettyPrint());
^
required: Iterable<F>,Function<? super F,? extends T#1>
found: List<CAP#1>,Function<ASTNode<?>,String>
reason: cannot infer type-variable(s) F,T#1,T#2
(argument mismatch; Function<CAP#1,String> cannot be converted to Function<? super CAP#1,? extends String>)
where F,T#1,T#2 are type-variables:
F extends Object declared in method <F,T#1>transform(Iterable<F>,Function<? super F,? extends T#1>)
T#1 extends Object declared in method <F,T#1>transform(Iterable<F>,Function<? super F,? extends T#1>)
T#2 extends ASTNode<?> declared in method <T#2>prettyPrint()
where CAP#1 is a fresh type-variable:
CAP#1 extends ASTNode<?> from capture of ? extends ASTNode<?>
1 error
(Perhaps notable is that Eclipse, configured for 1.8 compatibility, has no issues with this code).
Is this a compiler bug? If not, then assuming I'm allowed to change AstFunctions
and Main
(but not ASTNode
, List
, Function
, or Iterables
), how can I make this code compile? I'd also like to understand, if possible, what change to Java 8's type system makes this code not compile.
UPDATE: see other answer - this was a bug in javac which has been fixed.
It feels like this should not compile and that Java 8 is exhibiting the correct behaviour:
Iterables.transform
expects anIterable<F> fromIterable
andFunction<? super F...
, so the first generic type ofFunction
needs to be a super class of the generic type of theIterable
- in your main, the type of the Iterable is
F1 == ? extends ASTNode<?>
and the first type of the Function returned byprettyPrint
isF2 == T extends ASTNode<?>
I don't think there is a way to prove that F2 is a supertype of F1. For example let's say you have:
class A1 extends ASTNode<A1> {}
class A2 extends ASTNode<A2> {}
and in your main:
List<? extends ASTNode<?>> list = new List<A1>(); //F1 = A1
You could imagine that prettyPrint
returns a Function<A2, String>
(i.e. F2 = A2
) and A2 is not a super class of A1.
So I believe the compile error makes sense. But I won't try to prove it based on the specifications because that would eat most of my day!
这篇关于使用java 8中的泛型类型错误,而不是java 7的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!