在java 8下使用generics键入错误,但不是java 7
我有一段代码在java 7下编译得很好,但不是在java 8下编译。这是一个独立的再现示例(我已经采用了真实的代码来展示这个问题并且删除了所有的实现):
import java.util.Iterator; class ASTNode implements Iterable { @Override public Iterator iterator() { return null; } } class List extends ASTNode {} interface Function {} class Iterables { public static Iterable transform( Iterable fromIterable, Function function) { return null; } } class AstFunctions { public static <T extends ASTNode> Function prettyPrint() { return null; } } public class Main { public static void test() { List<? extends ASTNode> list = null; Iterables.transform(list, AstFunctions.prettyPrint()); } }
见证人:
$ 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,Function found: List,Function<ASTNode,String> reason: cannot infer type-variable(s) F,T#1,T#2 (argument mismatch; Function cannot be converted to Function) where F,T#1,T#2 are type-variables: F extends Object declared in method transform(Iterable,Function) T#1 extends Object declared in method transform(Iterable,Function) T#2 extends ASTNode declared in method prettyPrint() where CAP#1 is a fresh type-variable: CAP#1 extends ASTNode from capture of ? extends ASTNode 1 error
(或许值得注意的是,Eclipse配置为1.8兼容性,此代码没有问题)。
这是编译器错误吗? 如果没有,那么假设我被允许更改AstFunctions
和Main
(但不是ASTNode
, List
, Function
或Iterables
),我该如何编译这段代码呢? 我还想了解,如果可能的话,对Java 8类型系统的哪些更改会导致此代码无法编译。
更新:看到其他答案 – 这是javac中已修复的错误。
感觉这不应该编译,Java 8表现出正确的行为:
-
Iterables.transform
需要一个Iterable
和fromIterable Function super F...
Function super F...
,因此第一个generics类型的Function
需要是Iterable
的generics类型的超类 - 在你的主要,Iterable的类型是
F1 == ? extends ASTNode>
F1 == ? extends ASTNode>
并且prettyPrint
返回的函数的第一种类型是F2 == T extends ASTNode>
我认为没有办法certificateF2是F1的超级型。 例如,假设你有:
class A1 extends ASTNode {} class A2 extends ASTNode {}
在你的主要:
List extends ASTNode>> list = new List(); //F1 = A1
你可以想象prettyPrint
返回一个Function
(即F2 = A2
),A2不是A1的超类。
所以我相信编译错误是有道理的。 但我不会试图根据规格来certificate它,因为那会占用我的大部分时间!
这在最后一个javac 9的当前版本的编译器中不是问题。 在进行任何其他考虑之前,应根据此版本检查任何明显的错误。
对于最后一个javac8代码,要检查的存储库是最后一个javac 8 。 此问题已在该存储库中修复。 JDK-8033718的补丁修复了该问题