您能详细解释一下为什么预期结果不正确吗?正如大多数读者期望的输出是Byte Char Int Byte,但这当然不是正确的答案。
public class Tester {
public static String test(byte b) {
return "Byte ";
}
public static String test(char c) {
return "Char ";
}
public static String test(int i) {
return "Int ";
}
public static void main(String[] args) {
byte b = 0;
char c = 'A';
System.out.print(test(true ? b : c));
System.out.print(test(false ? b : c));
System.out.print(test(true ? 0 : 'A'));
System.out.print(test(false ? 'A' : (byte)0));
}
}
Run Code Online (Sandbox Code Playgroud)
正确的结果是Int Int Char Int.
这是因为重载解析取决于参数表达式的编译时类型,而不是参数的运行时类型。参见 JLS 15.12.2.2:
参数表达式的true ? b : c类型为int,因此Int调用该方法。这是在JLS 15.25.2中指定的,其中表示如果没有任何特殊情况匹配(这里都没有匹配),则条件表达式的类型是对第二个和第三个操作数应用数字提升后的类型:
如果表达式是以下之一,则该表达式将出现在数字选择上下文中:
- 数值条件表达式的第二个或第三个操作数
- [...]
数字提升确定数字上下文中所有表达式的提升类型。[...]规则如下:
short[...](在 a和 a表达式的情况下,这些规则都不匹配byte)否则,所有表达式都不是 double、float 或 long 类型。在这种情况下,上下文的种类决定了如何选择提升的类型。
在数字选择上下文中,适用以下规则:
short[...](在 a和 a表达式的情况下,这些规则都不匹配byte)否则,提升的类型为
int,并且所有非类型的表达式int都会经历扩展基元转换为int。
这就是为什么true ? b : c是类型的原因int。false ? b : c和也是如此false ? 'A' : (byte)0。条件是什么并不重要。表达式的类型由第二个和第三个操作数的类型决定。
至于test(true ? 0 : 'A'),这可以用我上面省略的规则来解释,就在最后一个“否则......”之前
- 否则,如果任何表达式的类型为
char,并且每个其他表达式都是类型char或类型的常量表达式,int并且其值可以在 类型中表示char,则提升的类型为char,并且int表达式将经历缩小原始转换为char。
在这种情况下,表达式“ ”是“具有可在该类型中表示的值0的类型的常量表达式”。intchar
考虑条件表达式类型的一种方法是,它是两个分支的表达式可以“适合”的最小类型。对于 abyte b和 a char c,int是可以同时容纳它们的最小类型。对于0、 和'A',char足以满足两者的要求,因为已知 的0范围是char。