Перегрузка Java: число, число; ИНТ, Double
Через два дня у меня есть экзамен в 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,Object
.
Но почему a.foo(5,1.2f);
также вызывает метод Number,Number
, а не метод int,Double
?
Но еще одна вещь, которая может быть полезна:
Если я удалю f
после 1.2
, так что вызов будет следующим:
a.foo(5,1.2);
Я получаю ошибку компилятора, что он не может выбирать между методами Number,Number
и int,Double
...
Было бы очень полезно, если бы вы, ребята, могли мне это объяснить:)
Ответы
Ответ 1
1.2f
не обернут Double
, он завернут Float
. Поскольку Float
не является подклассом Double
(они являются отдельными подклассами Number
), наиболее специфичной сигнатурой метода может быть foo(Number,Number)
.
Как только вы удалите f
, 1.2 по умолчанию будет обрабатываться Double
(примитив, а не класс-оболочка), который может быть автобоксирован в Double
. Однако 5 также может быть автобоксирован до Integer
, что вызывает неоднозначность.
Ответ 2
Здесь есть два важных фактора.
Во-первых, 1.2f
не является Double
. Это a Float
. Функция (int, Double)
не совпадает вообще. (Number, Number)
лучше всего подходит.
Во-вторых, даже когда вы меняете его на 1.2
, он по-прежнему не является Double
. Это Double
. То есть, это примитив, а не объект. Теперь Java все равно с удовольствием передаст Double
в функцию, которая хочет Double
без большой жалобы, но в этом случае вы путаете ее, предоставив ей два действительных преобразования, которые она могла бы сделать:
- Преобразуйте
5
в Integer
и конвертировать 1.2
в Double
- Оставьте
5
как примитив int
, но преобразуйте 1.2
в Double
.
Не существует правила, для которого предпочтительнее. Java создает ошибку компилятора, в которой он имеет неоднозначный вызов функции, и заставляет выбрать тот вариант, который вы предпочитаете (вручную обертывая один или оба из них в объекты).
В стороне, если у вас был метод, который принял (int, Double)
, не было бы никакой двусмысленности вообще: этот метод фактически соответствует существующим типам 5
и 1.2
, поэтому он будет вызван. Это тот факт, что некоторые из аргументов здесь являются объектами-оболочками, вызывающими хаос.
Ответ 3
Общий ответ:
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
*/
}
}