在java 8下使用泛型键入错误,但不是java 7

Ism*_*awi 12 java eclipse generics java-8

我有一段代码可以在java 7下编译,但不是在java 8下编译.这是一个独立的再现示例(我已经采用了真正的代码来展示这个问题并且删除了所有的实现):

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());
  }
}
Run Code Online (Sandbox Code Playgroud)

见证人:

$ 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
Run Code Online (Sandbox Code Playgroud)

(或许值得注意的是,Eclipse配置为1.8兼容性,此代码没有问题).

这是编译器错误吗?如果没有,那么假设我被允许改变AstFunctionsMain(但不包括ASTNode,List,Function,或Iterables),我怎样才能使此代码编译?我还想了解,如果可能的话,对Java 8类型系统的哪些更改会导致此代码无法编译.

Vic*_*ero 6

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

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


ass*_*ias 3

更新:请参阅其他答案 - 这是 javac 中的一个错误,现已修复。


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

  • Iterables.transform需要一个Iterable<F> fromIterableand Function<? super F...,所以第一个泛型类型Function需要是泛型类型的超类Iterable
  • 在你的 main 中,Iterable 的类型是F1 == ? extends ASTNode<?>,返回的 Function 的第一个类型prettyPrintF2 == T extends ASTNode<?>

我认为没有办法证明F2是F1的超类型。例如,假设您有:

class A1 extends ASTNode<A1> {}
class A2 extends ASTNode<A2> {}
Run Code Online (Sandbox Code Playgroud)

并在你的主要内容中:

List<? extends ASTNode<?>> list = new List<A1>(); //F1 = A1
Run Code Online (Sandbox Code Playgroud)

您可以想象prettyPrint返回 a Function<A2, String>(即F2 = A2) 并且 A2 不是 A1 的超类。

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

  • 这个答案是错误的,最新版本的 javac8 和 javac9 在接受程序方面与 ecj 一致,请参阅@Vicente Romero 的答案。 (2认同)