Разрешение перегрузки, какой метод вызывается - PullRequest
8 голосов
/ 22 января 2020

Предположим, у меня есть класс ComponentBase, который является потомком ObjectContextDecorator и внуком ObjectContext.

public class ComponentBase extends ObjectContextDecorator {
}

public class ObjectContextDecorator extends ObjectContext {

    public void set(String objectTypePath, String characteristicName, Object value) {
        //...
    }
}

public class ObjectContext {
    public void set(String characteristicName, Object value, boolean forced) {
       //...
    }
}

Методы set для ObjectContextDecorator и ObjectContext являются очень похожий. Рассмотрим следующий пример кода:

ComponentBase base = new ComponentBase();
base.set(""OTM4E_EFFLEVEL"", ""IE1 / STD"", true);

Подписи обоих методов соответствуют названию, вызываемому правильно. Я не могу изменить сигнатуры методов, поскольку это не мой код.

Как компилятор узнает, какой метод я намеревался вызвать?

Я знаю, что в IDE вы можете указать какой метод вы на самом деле намереваетесь вызвать, но в этой ситуации я использую загрузчик классов для загрузки класса, у которого есть метод, содержащий образец кода.

Ответы [ 2 ]

4 голосов
/ 22 января 2020

Все это объясняется в JLS §15.2 Выражения вызова метода. Он расскажет вам все о том, как выбран правильный метод для вызова. И обратите внимание, что это не всегда успешно.

В вашем конкретном случае c эти два метода являются перегрузками друг друга, поэтому применяется §15.2.2 «Шаг 2 времени компиляции: определение сигнатуры метода» - какая перегрузка для вызова определяется во время компиляции. Этот шаг далее делится на 3 этапа.

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

На первом этапе компилятор пытается найти подходящие методы, не допуская преобразования в боксы. В вашем случае, чтобы вызвать перегрузку, которая принимает Object, необходимо преобразование в бокс для преобразования boolean true в тип Object, чтобы перегрузка не была выбрана на первом этапе.

Если не найдено ни одного метода, применимого к строгому вызову, поиск применимых методов продолжается с этапа 2 (§15.12.2.3).

В противном случае наиболее конкретный c метод ( §15.12.2.5) выбирается из методов, которые применяются при строгом вызове.

Ну, мы нашли ровно один метод, поэтому мы просто выберем этот метод. Здесь нет двусмысленности.

2 голосов
/ 22 января 2020

Как компилятор узнает, какой метод я намеревался вызвать?

Он проверяет аргументы и определяет, какой из них является более точным c, следуя описанным правилам JLS §15.2

В вашем случае, вызов:

base.set("OTM4E_EFFLEVEL", "IE1 / STD", true)

аргументы String, String, boolean

Что соответствует первый класс ( имена параметров изменены для краткости )

public class ObjectContext {
    public void set(String s, Object o, boolean b){
       //...
    }
}

Второй класс не вызван, потому что третий параметр Object:

public class ObjectContextDecorator extends ObjectContext {

    public void set(String s, String ss, Object thisOneRightHere) {
        //...
    }
}

, и, хотя логическое значение true может совпадать, если оно автоматически занесено в коробку, первое значение будет более точным c. Здесь применяется следующее правило:

На первом этапе (§15.12.2.2) выполняется разрешение перегрузки без , разрешающее преобразование в бокс или распаковку

Но, например, если вы используете обертку объекта Boolean в подписи:

public class ObjectContext {
    public void set(String s, Object o, Boolean b){ //<-- third param changed from boolean to Boolean
       //...
    }
}

Тогда они оба будут совпадать, и компилятор сообщит вам следующее сообщение :

> A.java:25: error: reference to set is ambiguous
>     base.set("OTM4E_EFFLEVEL", "IE1 / STD", true);
>         ^   both method set(String,Object,Boolean) in ObjectContext and method set(String,String,Object) in ObjectContextDecorator match

Но это не так в вашем примере.

...