在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兼容性,此代码没有问题)。

这是编译器错误吗? 如果没有,那么假设我被允许更改AstFunctionsMain (但不是ASTNodeListFunctionIterables ),我该如何编译这段代码呢? 我还想了解,如果可能的话,对Java 8类型系统的哪些更改会导致此代码无法编译。

更新:看到其他答案 – 这是javac中已修复的错误。


感觉这不应该编译,Java 8表现出正确的行为:

  • Iterables.transform需要一个Iterable fromIterableFunction Function ,因此第一个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> list = new List(); //F1 = A1 

你可以想象prettyPrint返回一个Function (即F2 = A2 ),A2不是A1的超类。

所以我相信编译错误是有道理的。 但我不会试图根据规格来certificate它,因为那会占用我的大部分时间!

这在最后一个javac 9的当前版本的编译器中不是问题。 在进行任何其他考虑之前,应根据此版本检查任何明显的错误。

对于最后一个javac8代码,要检查的存储库是最后一个javac 8 。 此问题已在该存储库中修复。 JDK-8033718的补丁修复了该问题