类型推断的差异JDK8 javac / Eclipse Luna? [英] Differences in type inference JDK8 javac/Eclipse Luna?
问题描述
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(){
对象代码=test;
toString(getKey(code,null));
}
}
我认为唯一可能匹配的签名是toString (Object)。
当然我可以简单地向Object添加一个转换,但我想知道为什么javac不能自己违反类型(而eclipse),以及为什么javac认为Throwable和char []适合匹配,而不是Object。
这是Eclipse或javac中的错误吗? (我的意思是只有一个编译器可以在这里,无论是编译还是不编译)
编辑:javac(JDK8)的错误消息:
C:\XXXX\Workspace\XXXX\src> javac -cp。 TypeInferenceTest.java
TypeInferenceTest.java:22:error:引用toString是不明确的
toString(getKey(code,null));
^
TypeInferenceTest中的方法toString(char [])和TypeInferenceTest中的方法toString(Throwable)匹配
1错误
编译器只能检查方法签名,而不是方法体,使部分无关。
这个减少您的代码到(psuedocode):
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(){
对象代码=test;
toString(getKey(code,null));
}
}
另请注意, ; U> U getKey(...)
的确是:< U extends Object> U getKey(...)
。
所有它都知道 getKey(code,null)
返回是:?扩展Object
,所以它返回一个子类型 Object
或一个 Object
本身。 br>
有三个匹配的签名,即 Object
, char []
和 Throwable
,其中 char []
和 Throwable
code> Object ,因为你要求一个?扩展对象
。
所以它不能选择哪一个是正确的,因为所有三个匹配的签名。
当您将其更改为:
public static Object getKey(Object code,Object defaultValue);
然后只有 public static String toString(Object obj);
匹配,因为它与更好地匹配任何其他?扩展对象
不等于 Object
。
编辑,我查看了这个问题的原始意图:为什么它在Java 7中编译,但不是在Java 8中编译?
在Java 8中,类型推断得到很大的改善
而在Java 7中,例如只能推断出 getKey
返回一个对象
,它现在在Java 8推测它返回一个?扩展对象
。
当使用Java 7时,只有一个匹配,即 Object
。
为了使更改可视化更好,请考虑这段代码:
public class TypeInferenceTest {
public static String toString(Object obj){return1; }
public static String toString(Throwable t){return2; }
public static< U> U getKey(Object code,U defaultValue){return defaultValue; }
public static void test(){
对象代码=test;
String result = toString(getKey(code,null));
System.out.println(result);
}
public static void main(String [] args){
test();
}
}
在Java 7上打印 1
,在Java 8上,它打印 2
,正是由于上述原因。
I'm trying to switch a project to Java8, and encounter odd differences between Eclipse Luna and javac's type inference. With JDK 1.7.0_65 javac this code compiles just fine. JDK 1.8.0_11 complains that both toString(char[]) and toString(Throwable) match for the "toString(getKey(code, null));" line. Eclipse Luna 4.4 (I20140606-1215) compiles it happily with either 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));
}
}
I think the only signature that could possibly match is toString(Object).
Of course I could simply add a cast to Object, but I wonder why javac can't infere the type by itself (while eclipse does), and why the heck javac considers Throwable and char[] suitable matches, but not Object.
Is this a bug in Eclipse or javac? (I mean only one compiler can be right here, either it compiles or it doesn't)
Edit: Error message from 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
Compilers can only inspect the method signatures, not the method body, so that part is irrelevant.
This "reduces" your code to (psuedocode):
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));
}
}
Also note that the <U> U getKey(...)
really is: <U extends Object> U getKey(...)
.
All it knows that getKey(code, null)
returns is: ? extends Object
, so it returns a subtype of Object
, or an Object
itself.
There are three signatures that match, namely Object
, char[]
and Throwable
, where both char[]
and Throwable
match equally and better than Object
, because you asked for an ? extends Object
.
So it cannot choose which is the correct one, because all three match the signature.
When you change it to:
public static Object getKey(Object code, Object defaultValue);
then only public static String toString(Object obj);
matches, because it matches better as any other ? extends Object
that is not equal to Object
.
Edit, I looked over the original intent of the question: Why does it compile in Java 7, but not in Java 8?
In Java 8 type inference got greatly improved.
Whereas in Java 7 it could for example only infer that getKey
returned an Object
, it now in Java 8 infers that it returns an ? extends Object
.
When using Java 7 there was only one match, namely Object
.
To have the change visualized even better, consider this piece of code:
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();
}
}
On Java 7 it prints 1
, on Java 8 it prints 2
, exactly because of the reasons I have outlined above.
这篇关于类型推断的差异JDK8 javac / Eclipse Luna?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!