Java重载:数字,数字;整数,双精度

Java重载:数字,数字;整数,双精度,java,overloading,Java,Overloading,两天后我有一次java考试,我想不出这个问题的答案: class ClassA { public String foo(Integer x , int y) { return "Integer, int"; } public String foo(int x, Double y) { return "int, Double"; } public String foo(Number x, Number y) { return "Number, Number"; } pub

两天后我有一次java考试,我想不出这个问题的答案:

class ClassA {
 public String foo(Integer x , int y) {
  return "Integer, int";
 }
 public String foo(int x, Double y) {
  return "int, Double";
 }
 public String foo(Number x, Number y) {
  return "Number, Number";
 }
 public String foo(Object x, Object y) {
  return "Object, Object";
 }
 public static void main(String... args) {
  ClassA a = new ClassA();
  System.out.print(a.foo(5, 1.2f) + " ");
  System.out.println(a.foo(null, null));
 }
}
输出是什么

答案是:

Number, Number Number, Number
我知道java总是选择最指定的方法,这就是为什么
a.foo(null,null)
将激活
Number,Number
方法,而不是
对象,Object
方法。 但是为什么
a.foo(5,1.2f)
还可以使用
Number,Number
方法,而不是
int,Double
方法

但还有一件事可能会有所帮助: 如果在
1.2
之后删除
f
,则调用为:
a.foo(5,1.2)
我得到一个编译器错误,它不能在
Number,Number
int,Double
方法之间进行选择


如果你们能给我解释一下的话,那将非常有帮助:)

1.2f
不是用
双精度
包装的,而是用
浮点数
包装的。由于
Float
不是
Double
的子类(它们是
Number
的不同子类),因此可以使用的最具体的方法签名是
foo(Number,Number)


一旦删除
f
,1.2在默认情况下将被视为
double
(原语,而不是包装类),可以自动装箱到
double
。但是,5也可以自动装箱为整数,从而导致歧义。

这里有两个重要因素

首先,
1.2f
不是一个
Double
。这是一个
浮动
(int,Double)
函数根本不匹配<代码>(数字,数字)
是最合适的

第二,即使您将其更改为
1.2
,它仍然不是
Double
。它是一个
。也就是说,它是一个基本体,而不是一个对象。现在,Java仍然会很高兴地将一个
double
传递到一个需要
double
的函数中,而不会有太多抱怨,但是在这种情况下,您给了它两个有效的转换,从而混淆了它:

  • 5
    转换为
    整数
    并将
    1.2
    转换为
    双精度
  • 5
    保留为原语
    int
    ,但将
    1.2
    转换为
    Double
  • 没有一条规则规定哪一个更可取。Java产生一个编译器错误,即它有一个不明确的函数调用,并迫使您选择您喜欢的函数(通过手动将它们中的一个或两个包装到对象中)

    另一方面,如果您有一个使用
    (int,double)
    的方法,那么就不会有任何歧义:该方法实际上与
    5
    1.2
    的现有类型相匹配,因此将调用它。事实上,这里的一些参数是导致混乱的包装器对象。

    一般答案:

    public class OverloadingNumeric {
    
        public void print(int x){
            System.out.println("int");
        }
    
        public void print(long x){
            System.out.println("long");
        }
    
        public void print(float x){
            System.out.println("float");
        }
    
        public void print(double x){
            System.out.println("double");
        }
    
        public void print(Integer x){
            System.out.println("Integer");
        }
    
        public void print(Long x){
            System.out.println("Long");
        }
    
        public void print(Float x){
            System.out.println("Float");
        }
    
        public void print(Double x){
            System.out.println("Double");
        }
    
        public void print(Number x){
            System.out.println("Double");
        }
    
        public void print(Object x){
            System.out.println("Object");
        }
    
        public static void main(String[] args) {
            OverloadingNumeric obj = new OverloadingNumeric();
            /*
             * Primitives will take more precedence
             * of calling instead of wrapper class arguments,
             */
            obj.print(10);
            obj.print(10l);
            obj.print(10f);
            obj.print(10d);
            obj.print(10.1);
            //obj.print(999999999999999); Error: this letral type int is out of range
            obj.print(999999999999999l); 
    
            /*
             * OUTPUT
             * int
             * long
             * float
             * double
             * double
             * long
             */
    
    
    
            /*
             * Assume all primitive argument methods
             *  are commented. then calling the same again
             */
            obj.print(10);
            obj.print(10l);
            obj.print(10f);
            obj.print(10d);
            obj.print(10.1);
    
            //obj.print((Double)10); //Cannot cast int to Double 
            obj.print((double)10); //Success 
            //obj.print((Float)10); //Cannot cast int to Float 
            obj.print((float)10); //Success 
            //obj.print(null); ERROR AMBIGUOUS
    
            /*
             * OUTPUT
             * Integer
             * Long
             * Float
             * Double
             * Double
             * Double
             * Float
             * 
             */
        }
    }
    
    
    
    
    interface SuperIfc {}
    
    class SuperClass implements SuperIfc{}
    
    class SubClass extends SuperClass {}
    
    public class OverloadingTest {
    
        public void print(SuperIfc x){
            System.out.println("SuperIfc");
        }
    
        public void print(SuperClass x){
            System.out.println("SuperClass");
        }
    
        public void print(SubClass x){
            System.out.println("SubClass");
        }
    
        public void print(Object x){
            System.out.println("Object");
        }
    
        public static void main(String[] args) {
            OverloadingTest obj = new OverloadingTest();
            SuperClass superObj = new SuperClass();
            SubClass subObj = new SubClass();
            obj.print(superObj);
            obj.print(subObj);
            obj.print(null);
    
            obj.print((SuperIfc)superObj);
            obj.print((SuperIfc)subObj);
            obj.print((SuperIfc)null);
            /*
             *  OUTPUT
             * SuperClass
             * SubClass
             * SubClass
             * SuperIfc
             * SuperIfc
             * SuperIfc
             */
        }
    }
    

    (这解释了null,null)。浮点数的大小写很简单。好的,我想我已经理解了:)所以因为
    1.2f
    被视为浮点数,它只能自动装箱到
    Float
    而不能自动装箱到
    Double
    。但是,如果我将
    Double
    更改为
    Double
    ,它会起作用,因为在包装类中不可能使用
    Double