类型推断的差异JDK8 javac/Eclipse Luna?

Dur*_*dal 6 java eclipse type-inference javac

我正在尝试将项目切换到Java8,并且遇到Eclipse Luna和javac类型推断之间的奇怪差异.使用JDK 1.7.0_65 javac,这段代码编译得很好.JDK 1.8.0_11抱怨toString(char [])和toString(Throwable)都匹配"toString(getKey(code,null));" 线.Eclipse Luna 4.4(I20140606-1215)使用JDK快乐地编译它:

public class TypeInferenceTest {
    public static String toString(Object obj) {
        return "";
    }

    public static String toString(char[] ca) {
        return "";
    }

    public static String toString(Throwable t) {
        return "";
    }

    public static <U> U getKey(Object code, U defaultValue) {
        return defaultValue;
    }

    public static void test() {
        Object code = "test";
        toString(getKey(code, null));
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为唯一可能匹配的签名是toString(Object).

当然我可以简单地向Object添加一个强制转换,但我想知道为什么 javac不能自己推断类型(虽然eclipse确实如此),以及为什么heck javac认为Throwable和char []合适的匹配,而不是Object.

这是Eclipse或javac中的错误吗?(我的意思是只有一个编译器可以在这里,无论是编译还是不编译)

编辑:来自javac(JDK8)的错误消息:

C:\XXXX\Workspace\XXXX\src>javac -cp . TypeInferenceTest.java
TypeInferenceTest.java:22: error: reference to toString is ambiguous
                toString(getKey(code, null));
                ^
  both method toString(char[]) in TypeInferenceTest and method toString(Throwable) in TypeInferenceTest match
1 error
Run Code Online (Sandbox Code Playgroud)

ski*_*iwi 3

编译器只能检查方法签名,而不能检查方法主体,因此该部分是不相关的。

这将您的代码“减少”为(伪代码):

public class TypeInferenceTest {
    public static String toString(Object obj);

    public static String toString(char[] ca);

    public static String toString(Throwable t);

    public static <U> U getKey(Object code, U defaultValue);

    public static void test() {
        Object code = "test";
        toString(getKey(code, null));
    }
}
Run Code Online (Sandbox Code Playgroud)

另请注意,<U> U getKey(...)实际上是:<U extends Object> U getKey(...)

它只知道getKey(code, null)返回的是:? extends Object,因此它返回 的子类型Object,或者它Object本身。
有 3 个匹配的签名,即Objectchar[]Throwable,其中 和char[]Throwable匹配并且比 匹配得更好Object,因为您要求的是? extends Object

因此它无法选择哪一个是正确的,因为所有三个都与签名匹配。

当你将其更改为:

public static Object getKey(Object code, Object defaultValue);
Run Code Online (Sandbox Code Playgroud)

then 只public static String toString(Object obj);匹配,因为它比任何其他不等于 的匹配更好? extends ObjectObject

编辑,我查看了问题的初衷:为什么它可以在 Java 7 中编译,但不能在 Java 8 中编译?

在 Java 8 中,类型推断得到了极大的改进。

例如,在 Java 7 中它只能推断getKey返回一个Object,而现在在 Java 8 中它只能推断它返回一个? extends Object

使用 Java 7 时只有一个匹配项,即Object.

为了更好地可视化更改,请考虑这段代码:

public class TypeInferenceTest {
    public static String toString(Object obj) { return "1"; }

    public static String toString(Throwable t) { return "2"; }

    public static <U> U getKey(Object code, U defaultValue) { return defaultValue; }

    public static void test() {
        Object code = "test";
        String result = toString(getKey(code, null));
        System.out.println(result);
    }

    public static void main(String[] args) {
        test();
    }
}
Run Code Online (Sandbox Code Playgroud)

在 Java 7 上它打印1,在 Java 8 上它打印2,正是因为我上面概述的原因。