使用java 8中的泛型类型错误,而不是java 7 [英] Type error using generics under java 8, but not java 7

查看:839
本文介绍了使用java 8中的泛型类型错误,而不是java 7的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  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 an Iterable<F> fromIterable and Function<? super F..., so the first generic type of Function needs to be a super class of the generic type of the Iterable
  • in your main, the type of the Iterable is F1 == ? extends ASTNode<?> and the first type of the Function returned by prettyPrint is F2 == 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆