我知道这个问题多次讨论过,但我还是不明白.
研究这段代码:
public class Main {
public static void var(Integer x, int y) {
System.out.println("Integer int");
}
public static void var(int... x) {
System.out.println("int... x");
}
public static void var(Integer... x) {
System.out.println("Integer...");
}
public static void main(String... args) {
byte i = 0;
Integer i2 = 127;
var(i, i2);
}
}
Run Code Online (Sandbox Code Playgroud)
在我的大脑遵循规则:
加宽
拳击
拳+可变参数
根据这条规则,我会做下一步行动
1.byte扩展到int
现在我有int Integer ,并且存在方法需要Integer和int
2.make拳击
因此.int- > Integer和Integer- > int参数
我认为这些论点是适用的,并且有望看到
Integer int
Run Code Online (Sandbox Code Playgroud)
在输出中.
但我明白了
int ...
Run Code Online (Sandbox Code Playgroud)
为什么?
现在很清楚,该方法var(int...)是选择的而不是var(Integer...).
原因是只允许应用某些转换,并且它只能是列表中的其中一个转换,而不是转换链.首先不允许java编译器进行扩展原语转换,然后进行装箱转换.
5.3.方法调用转换
方法调用转换应用于方法或构造函数调用中的每个参数值(第8.8.7.1节,第15.9节,第15.12节):必须将参数表达式的类型转换为相应参数的类型.
方法调用上下文允许使用_以下_ 之一:
- 身份转换(§5.1.1)
- 扩展的原始转换(第5.1.2节)
- 扩大参考转换(第5.1.5节)
- 一个拳击转换(§5.1.7)可选地后面加宽引用转换
- 一个拆箱转换(第5.1.8节),可选地后跟一个加宽的基元转换.
编译器的唯一选择是:
那变成(byte, Integer)了(int, int).
它不能先将第一个参数byte转换为a int然后对来自的相同参数应用装箱转换int,Integer因为不允许按顺序进行两次转换.
让我们回过头来了解编译器如何选择要调用的重载方法.这在JLS 15.12.2中有所描述.(15.12.1描述了如何查找要搜索的类或接口,但我们已经知道我们要在类中调用静态方法Main)
编译器选择正确重载方法的前两个阶段不适用于变量参数("变量arity")方法,但第三阶段确实如此:
第三阶段(§15.12.2.4)允许重载与变量arity方法,装箱和拆箱相结合.
第15.12.4节非常复杂,但适用的规则是:
所以..
var与(byte, Integer)var(Integer...)byte为Integer(方法中声明的参数类型)byte成Integer直接-它不能做两个步骤.var(Integer...)var(int...)byte为int使用扩展的原始转换.这是一个复选标记.Integer它看到JLS 5.3允许编译器将其转换为int使用拆箱转换.所以这也是一个复选标记.var(int...)是一个很好的匹配.var,所以var(int...)唯一适用的方法.编译器现在将生成代码以执行必要的转换并调用该方法.Java只能做到“框加宽”,不能做到“宽加框”。例如,
因此,在您给定的方法中,第一个参数字节已经使两个 Integer 方法失败。因此,只有 int... 适用。
我编写了以下演示类:
public class Overload{
public static void primitiveWiden(int x){
System.out.println("int");
}
public static void refWiden(Map m){
System.out.println("Map");
}
public static void priWideAndBox(Integer o){//doesn't work
System.out.println("Object");
}
public static void boxAndRefWide(Number n){//it works
System.out.println("Number");
}
public static void main(String[] args){
byte b =0;
int i =0;
HashMap m = new HashMap();
primitiveWiden(b);
refWiden(m);
priWideAndBox(b);//compile error
boxAndRefWide(i);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4058 次 |
| 最近记录: |