Java类型推理在编译时失败,但是Eclipse编译并运行良好



我很难理解为什么以下代码在Java 8/9中不编译,但是如果我从Eclipse IDE内部进行"运行",则可以正常运行,这很好。

package de.playground.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class InferenceTest {
    class InferenceObject<T> implements Comparable<InferenceObject<T>> {
        @Override
        public int compareTo(InferenceObject<T> o) {
            return 0;
        }
    }
    public static void main(String[] args) {
        InferenceTest inferenceTest = new InferenceTest();
        List<InferenceObject<?>> result = inferenceTest.read();
        System.out.println(String.format("Array contains %d element(s)", result.size()));
    }
    private List<InferenceObject<?>> read() {
        List<InferenceObject<?>> simpleList = new ArrayList<>();
        InferenceObject<String> infObj = new InferenceObject<>();
        simpleList.add(infObj);
        // Collections.<InferenceObject<?>>sort(simpleList);
        Collections.sort(simpleList);
        return simpleList;
    }
}

javac InferenceTest.java产生以下错误:

InferenceTest.java:26: error: no suitable method found for sort(List<InferenceTest.InferenceObject<?>>)
                Collections.sort(simpleList);
                           ^
    method Collections.<T#1>sort(List<T#1>) is not applicable
      (inference variable T#1 has incompatible bounds
        equality constraints: InferenceTest.InferenceObject<?>
        upper bounds: InferenceTest.InferenceObject<CAP#1>,Comparable<? super T#1>)
    method Collections.<T#2>sort(List<T#2>,Comparator<? super T#2>) is not applicable
      (cannot infer type-variable(s) T#2
        (actual and formal argument lists differ in length))
  where T#1,T#2 are type-variables:
    T#1 extends Comparable<? super T#1> declared in method <T#1>sort(List<T#1>)
    T#2 extends Object declared in method <T#2>sort(List<T#2>,Comparator<? super T#2>)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
1 error

问题是,由于使用的通配符仿制药而导致的推理失败 - 我很困惑此代码为何在Eclipse中编译,而Oracle JDK 8/9拒绝编译此代码 - 可能是回归的回归。错误6468354?

二手环境:Kubuntu 17.10 X86_64,Javac 1.8.0,Javac 1.8.0_131,Javac 1.8.0_151和Javac 9.0.0.0.1

解决方法:

class InferenceObject<T> implements Comparable<InferenceObject<?>> {
    @Override
    public int compareTo(InferenceObject<?> o) {
        return 0;
    }
}

在不明确说明类型而不是通配符通用的情况下,不使用略有不同的解决方法,编写此代码的正确方法是什么?

我很难理解为什么以下代码不 在Java 8/9

中编译

该代码不编译(使用1.8.0_161(,因为您要求 collections.sort((对未正确实现可比接口的类型的对象进行分类。从Javadoc for Collections.Sort((:

根据其元素的自然顺序,将指定的列表分为上升顺序。列表中的所有元素必须实现可比接口

在您的初始代码中,要排序的列表的成员为InferenceObject<?>类型,但是您 compareTo((方法的参数为InferenceObject<T>类型,因此有一个编译器错误是正确的。

如果 compareTo((方法的参数为(说(InferenceObject<Float>,则编译器错误的原因将更加清晰,并且要排序的列表由(例如(InferenceObject<LocalDate>对象组成。尽管原因不太明显,但在初始代码列表中也适用相同的原则。

如果您的列表包含实现的任何特定类型的可比性的特定类型的inferneoBjects,则您的原始inferenderObject类定义是可以的。例如:

List<InferenceObject<String>> simpleList = new ArrayList<>(); List<InferenceObject<BigInteger>> simpleList = new ArrayList<>(); List<InferenceObject<Year>> simpleList = new ArrayList<>();

我很困惑为什么此代码在Eclipse中编译

所以我是I。它看起来像是Eclipse编译器的错误。您可以提出一个错误报告。

在不明确说明的情况下编写此代码的正确方法是什么 类型而不是通配符通用

您已经在修订的代码中以正确的方式进行操作。您要么要创建类型InferenceObject<?>的对象列表(即输入未知(,要么要创建一个类型InferenceObject<T>的对象列表,其中't'是某种特定类型。这是二进制的选择。

(实际上比这更细微差别,因为您可以拥有List<InferenceObject<? extends Number>>,但我认为您没有问过。(

不使用略有不同的 orkaround

不要将其视为"解决方法"。将其视为正确编写代码的先决条件。

,但对您的代码的另一个值得更改将是声明 Simplelist ,因为您知道您想对其元素进行排序:

List<InferenceObject<? extends Comparable>> simpleList = new ArrayList<>();

然后,如果您尝试在列表中添加无效的推理对象,则编译器将标记错误:

simpleList.add(new InferenceObject<String>()); // OK, since String implements Comparable
simpleList.add(new InferenceObject<StringBuffer>()); // Error, since StringBuffer does not implement Comparable

最新更新