考虑以下程序:
public class GenericTypeInference {
public static void main(String[] args) {
print(new SillyGenericWrapper().get());
}
private static void print(Object object) {
System.out.println("Object");
}
private static void print(String string) {
System.out.println("String");
}
public static class SillyGenericWrapper {
public <T> T get() {
return null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
它在Java 8下打印"String",在Java 7下打印"Object".
我原以为这是Java 8中的歧义,因为两种重载方法都匹配.为什么编译器print(String)在JEP 101之后选择?
是否合理,这会破坏向后兼容性,并且在编译时无法检测到更改.升级到Java 8后,代码只是偷偷摸摸地表现不同.
注意:由于SillyGenericWrapper某种原因,它被命名为"愚蠢".我试图理解为什么编译器的行为方式,不要告诉我这个愚蠢的包装器首先是一个糟糕的设计.
更新:我还尝试在Java 8下编译和运行示例,但使用的是Java 7语言级别.这种行为与Java 7一致.这是预期的,但我仍然觉得需要验证.
以下是Java 7中的代码编译,但不是openjdk-1.8.0.45-31.b13.fc21.
static void f(Object o1, int i) {}
static void f(Object o1, Object o2) {}
static void test(boolean b) {
String s = "string";
double d = 1.0;
// The supremum of types 'String' and 'double' is 'Object'
Object o = b ? s : d;
Double boxedDouble = d;
int i = 1;
f(o, i); // fine
f(b ? s : boxedDouble, i); // fine
f(b ? s : d, i); // ERROR! Ambiguous
}
Run Code Online (Sandbox Code Playgroud)
编译器声称最后一个方法调用不明确.
如果我们改变的第二个参数的类型f …
有人可以帮助解释为什么测试 2 和测试 3 有问题吗?
public static void main (String[] args) {
byte b = 5;
doCalc(b, b);
}
Run Code Online (Sandbox Code Playgroud)
测试1:这两种方法没有歧义问题。
static void doCalc(byte a, byte b) {
System.out.print("byte, byte");
}
static void doCalc(Byte s1, Byte s2) {
System.out.print("Byte, Byte");
}
Run Code Online (Sandbox Code Playgroud)
测试2:这两个方法没有编译时二义性,但存在运行时二义性。
static void doCalc(Byte... a) {
System.out.print("byte 1...");
}
static void doCalc(long... a) {
System.out.print("byte 2...");
}
Run Code Online (Sandbox Code Playgroud)
测试3:这两个方法在编译时存在二义性。
static void doCalc(Byte... a) {
System.out.print("byte 1...");
}
static void doCalc(byte... a) {
System.out.print("byte 2...");
}
Run Code Online (Sandbox Code Playgroud)