【问题标题】:Type error using generics under java 8, but not java 7在 java 8 下使用泛型类型错误,但不是 java 7
【发布时间】:2014-05-22 04:42:50
【问题描述】:

我有一段代码在 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());
  }
}

证人:

$ 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

(也许值得注意的是,配置为兼容 1.8 的 Eclipse 对此代码没有任何问题)。

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

【问题讨论】:

  • 如果您尝试 Eclipse 的开发版本会发生什么?它可能无法解决编译器错误,但您可能能够从 Eclipse 中获取更多信息而不是破坏它
  • @user3580294 我刚刚尝试使用 4.4RC1 并得到完全相同的内部编译器错误:\
  • 哦,真的吗?我强烈建议您提交一份错误报告,因为我认为他们希望在 4.4 上线之前解决这个问题。很遗憾听到这不起作用...
  • 老实说,我认为这需要 SO 的 Java 8 专家之一(@BrianGoetz,也许?)来解决。我无法想象有很多人对 Java 的类型推断系统如何工作有足够的了解来快速回答这个问题......
  • @user3580294 我在这里提交了一个错误:bugs.eclipse.org/bugs/show_bug.cgi?id=435463

标签: java eclipse generics java-8


【解决方案1】:

last javac 9 的当前版本的编译器中,这不是问题。在考虑任何其他问题之前,应针对此版本检查任何明显的错误。

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

【讨论】:

  • 为什么需要针对 Java9(测试版)检查 Java8 错误? Java8 发布了几个月,并将在未来几年内得到支持。
  • @Durandal,对于超级迟到的答案,我的意思是,如果错误在 9 中得到修复,那么我们不是在谈论错误,而是在谈论应该向后移植到 java8 的变更集。这里的过程应该是检查最后一个 javac,如果它在那里修复,那么下一步就是找到产生影响的变更集。
  • compiler-dev@openjdk.java.net 应该是问这个问题的地方
【解决方案2】:

更新:查看其他答案 - 这是 javac 中的一个错误,已修复。


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

  • Iterables.transform 需要 Iterable&lt;F&gt; fromIterableFunction&lt;? super F...,所以Function 的第一个泛型类型需要是Iterable 泛型类型的超类
  • 在你的main中,Iterable的类型是F1 == ? extends ASTNode&lt;?&gt;,而prettyPrint返回的Function的第一个类型是F2 == T extends ASTNode&lt;?&gt;

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

class A1 extends ASTNode<A1> {}
class A2 extends ASTNode<A2> {}

在你的主要:

List<? extends ASTNode<?>> list = new List<A1>(); //F1 = A1

您可以想象prettyPrint 返回一个Function&lt;A2, String&gt;(即F2 = A2)并且A2 不是A1 的超类。

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

【讨论】:

  • 无论如何,我认为它归结为 Java 8 类型推断中的改进,它正确地检测到代码不正确。
  • 好的。好吧,我只是用普通循环替换了对Iterables.transform 的调用,而不是处理这些问题。不值得麻烦!
  • 有趣的是,至少有一位 Eclipse 维护者 thinks otherwise... 还没有来自 Oracle 的回复,而且认为不会很快有回复。
  • 这个答案是错误的,最近版本的 javac8 和 javac9 在接受程序方面与 ecj 一致,请参阅@Vicente Romero 的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-25
  • 2018-12-28
  • 2016-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多