Разрешение перегрузки метода в java

вот что я знаю о разрешении перегрузки в Java:


процесс компилятора, пытающегося Разрешить вызов метода из данного перегруженные определения методов называются разрешением перегрузки. Если компилятор не может найти точное совпадение выглядит на ближайший матч используя upcasts only (downcasts никогда не выполняются).


вот класс:

public class MyTest {

    public static void main(String[] args) {
        MyTest test = new MyTest();
        Integer i = 9;
        test.TestOverLoad(i);
    }

    void TestOverLoad(int a){
        System.out.println(8);
    }

    void TestOverLoad(Object a){
        System.out.println(10);
    }

}

как и ожидалось, выход равен 10.

однако, если я немного изменю определение класса и изменю второй перегруженный метод.

   public class MyTest {

        public static void main(String[] args) {
            MyTest test = new MyTest();
            Integer i = 9;
            test.TestOverLoad(i);
        }

        void TestOverLoad(int a){
            System.out.println(8);
        }

       void TestOverLoad(String a){
            System.out.println(10);
    }

}

выход 8.

здесь я в замешательстве. Если downcasting никогда не должен был использоваться, тогда почему 8 был напечатан вообще? Почему компилятор взял TestOverLoad метод, который принимает int в качестве аргумента, который является нисходящим от Integer до int?

5 ответов


компилятор рассмотрит не пониженное, а распакованное преобразование для разрешения перегрузки. Здесь Integer i будет распакован в int успешно. The String метод не рассматривается, потому что Integer невозможно расширить до String. Единственная возможная перегрузка-это та, которая рассматривает распаковку, поэтому 8 печати.

причина, по которой вывод первого кода 10 заключается в том, что компилятор рассмотрит расширяющееся преобразование ссылок (Integer до Object) над распаковкой преобразования.

раздел 15.12.2 JLS, рассматривая, какие методы применимы, заявляет:

  1. первая фаза (§15.12.2.2) выполняет разрешение перегрузки без разрешения бокса или распаковки преобразования или использования вызова метода переменной arity. Если на этом этапе не найден применимый метод, обработка продолжается до второго этапа.

  1. вторая фаза (§15.12.2.3)выполняет разрешение перегрузки, разрешая бокс и распаковку [...]

в Java разрешение методов в случае перегрузки метода выполняется со следующим приоритетом:

1. Расширение
2. Авто-бокс
3. Var-args

компилятор java считает, что расширение примитивного параметра более желательно, чем выполнение операции автоматического бокса.

другими словами, как авто-бокс был представлен в Java 5, компилятор выбирает более старый стиль (расширение) прежде чем выбрать новый стиль (авто-бокс), сохраняя существующий код более надежным. То же самое с var-args.

в вашем 1-м фрагменте кода происходит расширение ссылочной переменной i.e,Integer to Object вместо того, чтобы un-boxing i.e,Integer to int. И в вашем 2-м фрагменте расширение не может произойти из Integer to String так что распаковка происходит.

рассмотрим приведенную ниже программу, которая доказывает все вышеперечисленное заявления:

class MethodOverloading {

    static void go(Long x) {
        System.out.print("Long ");
    }

    static void go(double x) {
        System.out.print("double ");
    }

    static void go(Double x) {
        System.out.print("Double ");
    }

    static void go(int x, int y) {
        System.out.print("int,int ");
    }

    static void go(byte... x) {
        System.out.print("byte... ");
    }

    static void go(Long x, Long y) {
        System.out.print("Long,Long ");
    }

    static void go(long... x) {
        System.out.print("long... ");
    }

    public static void main(String[] args) {
        byte b = 5;
        short s = 5;
        long l = 5;
        float f = 5.0f;
        // widening beats autoboxing
        go(b);
        go(s);
        go(l);
        go(f);
        // widening beats var-args
        go(b, b);
        // auto-boxing beats var-args
        go(l, l);
    }
}

выход:

double double double double int,int Long,Long

просто для справки, вот мой блог о перегрузке метода в Java.

P. S: Мой ответ-Это модифицированная версия примера, приведенного в SCJP.


расширение бьет бокс, бокс бьет var-args. В вашем примере расширение не может произойти, поэтому бокс применяется и целое число распаковывается. Ничего необычного.


на самом деле во втором примере не происходит downcasting. Произошло следующее ... --12-->

1. Integer развернут/распакован в примитивный тип int.
2. тут TestOverLoad(int a) метод называется.

в основном методе вы объявляете целое число как -

 Integer i = 9;  
вызов -
test.TestOverLoad(i);  

в то время как у вас есть 2 перегруженная версия TestOverLoad() -

TestOverLoad(int a); 
TestOverLoad(String a);

здесь вторая перегруженная версия TestOverLoad() принимает совершенно другой аргумент String. Вот почему Integer i распаковывается в примитивный тип int и после этого вызывается первая перегруженная версия.


все объекты в Java расширяют объект класса, включая целое число класса. Эти два класса имеют следующее отношение: Integer" is a (n) " объект, потому что Integer расширяет объект. В первом примере используется метод с параметром Object.

во втором примере не найдено методов, которые принимают целое число. В этом случае Java использует то, что называется auto-unboxing, чтобы разрешить целочисленный класс-оболочку к примитиву int. Таким образом, метод с параметром int используемый.