java - 推理变量具有不兼容的界限。 Java 8 编译器回归?

标签 java compiler-errors java-8 type-inference

以下程序在 Java 7 和 Eclipse Mars RC2 for Java 8 中编译:

import java.util.List;

public class Test {

    static final void a(Class<? extends List<?>> type) {
        b(newList(type));
    }

    static final <T> List<T> b(List<T> list) {
        return list;
    }

    static final <L extends List<?>> L newList(Class<L> type) {
        try {
            return type.newInstance();
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

使用javac 1.8.0_45编译,报如下编译错误:

Test.java:6: error: method b in class Test cannot be applied to given types;
        b(newList(type));
        ^
  required: List<T>
  found: CAP#1
  reason: inference variable L has incompatible bounds
    equality constraints: CAP#2
    upper bounds: List<CAP#3>,List<?>
  where T,L are type-variables:
    T extends Object declared in method <T>b(List<T>)
    L extends List<?> declared in method <L>newList(Class<L>)
  where CAP#1,CAP#2,CAP#3 are fresh type-variables:
    CAP#1 extends List<?> from capture of ? extends List<?>
    CAP#2 extends List<?> from capture of ? extends List<?>
    CAP#3 extends Object from capture of ?

一种解决方法是在本地分配一个变量:

import java.util.List;

public class Test {

    static final void a(Class<? extends List<?>> type) {

        // Workaround here
        List<?> variable = newList(type);
        b(variable);
    }

    static final <T> List<T> b(List<T> list) {
        return list;
    }

    static final <L extends List<?>> L newList(Class<L> type) {
        try {
            return type.newInstance();
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

我知道类型推断在 Java 8 (e.g. due to JEP 101 "generalized target-type inference") 中发生了很大变化。那么,这是一个错误还是一个新的语言“功能”?

编辑:我也已将此问题作为 JI-9021550 报告给 Oracle,但以防万一这是 Java 8 中的“功能”,我也已向 Eclipse 报告了该问题:

最佳答案

免责声明 - 我对这个主题知之甚少,以下是我的非正式推理,试图证明 javac 的行为是正当的。


我们可以将问题简化为

<X extends List<?>> void a(Class<X> type) throws Exception
{
    X instance = type.newInstance();
    b(instance);  // error
}

<T> List<T> b(List<T> list) { ... }

推断 T , 我们有约束

      X <: List<?>
      X <: List<T>

本质上,这是无法解决的。例如,没有 T如果 X=List<?> 则存在.

不确定 Java7 如何推断这种情况。但我会说,javac8(和 IntelliJ)表现得“合理”。


现在,这个解决方法是如何工作的?

    List<?> instance = type.newInstance();
    b(instance);  // ok!

由于通配符捕获而起作用,它引入了更多类型信息,“缩小”了 instance 的类型

    instance is List<?>  =>  exist W, where instance is List<W>  =>  T=W

不幸的是,当 instanceX ,因此可以使用的类型信息较少。

可以想象,该语言也可以“改进”以对 X 进行通配符捕获:

    instance is X, X is List<?>  =>  exist W, where instance is List<W>

关于java - 推理变量具有不兼容的界限。 Java 8 编译器回归?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30622759/

相关文章:

ios - Xcode 中的错误 "Use of undeclared type"不会消失

java - IdeaUIDesigner 中的 Lambda 表达式和 Java 1.8

java - 如何计算 Java 8 中嵌套类结构中属性的总和?

java - 在控制层编写决策语句

java - Line 类的 Getter 方法

java - WebClient 在 JUnit 中导致 "java.lang.IllegalStateException: executor not accepting a task"

java - 删除 Int 的 ArrayList 中的连续值

java - 物的生死解说

macos - 如何在 macOS 上使用 OpenMPI、Hypre 和 Mumps 编译 Elmer fem

haskell - Haskell中的实际类型与预期类型错误