Подтвердить что ты не робот

Перегрузка - это полиморфизм времени компиляции. В самом деле?

Я знаю синтаксическую разницу между переопределением и перегрузкой. И я также знаю, что переопределение - это полиморфизм во время выполнения, а перегрузка - это полиморфизм времени компиляции. Но мой вопрос: "Является ли перегрузка действительно полиморфизмом времени компиляции? Является ли вызов метода действительно решающим во время компиляции?". Чтобы прояснить мою точку зрения, рассмотрим примерный класс.

public class Greeter {
    public void greetMe() {
        System.out.println("Hello");
    }

    public void greetMe(String name) {
        System.out.println("Hello " + name);
    }

    public void wishLuck() {
        System.out.println("Good Luck");
    }
}

Поскольку все методы greetMe(), greetMe(String name), wishLuck() являются общедоступными, все они могут быть переопределены (в том числе перегружены), правильно? Например,

public class FancyGreeter extends Greeter {
    public void greetMe() {
        System.out.println("***********");
        System.out.println("*  Hello  *");
        System.out.println("***********");
    }
}

Теперь рассмотрим следующий фрагмент:

Greeter greeter = GreeterFactory.getRandomGreeter();
greeter.greetMe();

Метод getRandomGreeter() возвращает случайный объект Greeter. Он может либо возвращать объект Greeter, либо любой из его подклассов, например FancyGreeter или GraphicalGreeter или любой другой. getRandomGreeter() создаст объекты либо с помощью new, либо динамически загрузит файл класса и создаст объект с использованием отражения (я думаю, что это возможно с отражением) или любым другим способом, который возможен. Все эти методы Greeter могут или не могут быть переопределены в подклассах. Поэтому компилятор не имеет возможности узнать, переопределен ли какой-либо конкретный метод (перегружен или нет). Правильно? Кроме того, wikipedia говорит о Виртуальные функции:

В Java все нестатические методы по умолчанию являются "виртуальными функциями".     Только методы, отмеченные ключевым словом final, которые нельзя переопределить,     наряду с частными методами, которые не унаследованы, не являются виртуальными.

Так как виртуальные функции разрешаются во время выполнения с помощью диспетчеризации динамических методов, и поскольку все не частные, но не окончательные методы являются виртуальными (независимо от того, перегружены они или нет), они должны быть разрешены во время выполнения. Правильно?

Затем, как перегрузка может быть разрешена во время компиляции? Или, есть ли что-то, что я неправильно понял, или мне не хватает?

4b9b3361

Ответ 1

Перегруженные методы все равно могут быть переопределены, если это то, о чем вы просите.

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

То есть, отправка метода выполняется в два этапа:

  • Первый выполняется во время компиляции с доступной статической информацией, компилятор будет генерировать call для подписи, которая наилучшим образом соответствует вашим текущим параметрам метода среди списка перегруженных методов в объявленном типе объекта. Метод вызывается.
  • Второй шаг выполняется во время выполнения, учитывая подпись метода, которая должна быть вызвана (предыдущий шаг, помните?), JVM отправит ее в наиболее конкретную переопределенную версию в фактическом типе объекта получателя.

Если типы аргументов метода не ковариантны вообще, перегрузка эквивалентна наличию имен методов, искаженных во время компиляции; потому что они эффективно отличаются друг от друга, JVM никогда не будет отправлять их взаимозаменяемо в зависимости от типа получателя.

Ответ 2

Каждый класс "Greeter" имеет 3 виртуальных метода: void greetMe(), void greetMe(String) и void wishLuck().

Когда вы вызываете greeter.greetMe(), компилятор может решить, какой из трех виртуальных методов следует вызывать из подписи метода, т.е. void greetMe(), поскольку он не принимает аргументов. Какая конкретная реализация метода void greetMe() вызывается, зависит от типа экземпляра greeter и разрешается во время выполнения.

В вашем примере тривиально, чтобы компилятор мог определить, какой метод вызывать, поскольку подписи метода полностью отличаются друг от друга. Немного лучший пример для иллюстрации концепции "компиляции временного полиморфизма" может быть следующим:

class Greeter {
    public void greetMe(Object obj) {
        System.out.println("Hello Object!");
    }

    public void greetMe(String str) {
        System.out.println("Hello String!");
    }
}

Использование этого класса greeter даст следующие результаты:

Object obj = new Object();
String str = "blah";
Object strAsObj = str;

greeter.greetMe(obj); // prints "Hello Object!"
greeter.greetMe(str); // prints "Hello String!"
greeter.greetMe(strAsObj); // prints "Hello Object!"

Компилятор выберет метод с наиболее конкретным совпадением с использованием типа времени компиляции, поэтому второй пример работает и вызывает метод void greetMe(String).

Последний вызов является самым интересным: даже несмотря на то, что тип времени выполнения strAsObj равен String, он был отличен как Object, так что компилятор видит его. Итак, самое близкое совпадение, которое может найти компилятор для этого вызова, - это метод void greetMe(Object).

Ответ 3

Что такое полиморфизм?

Acc. для меня: , если сущность может быть представлена ​​более чем в одной форме, эта сущность, как говорят, проявляет полиморфизм.

Теперь применим это определение к конструкциям Java:

1) Перегрузка оператора - это полиморфизм времени компиляции.

Например, оператор + может быть использован для добавления двух чисел ИЛИ для конкатенации двух строк. это пример полиморфизма, строго говоря, полиморфизма времени компиляции.

2) Перегрузка метода - это полиморфизм времени компиляции.

Например, метод с таким же именем может иметь более одного экземпляра. это также полиморфизм времени компиляции.

It compile-time because before execution of program compiler decides the flow of program i.e which form will be used during run-time.

3) Переопределение метода - это полиморфизм во время выполнения.

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

4) Использование базового класса вместо производного класса - это полиморфизм времени выполнения.

Например, ссылка interface может указывать на любой из ее разработчиков.

It run-time because the flow of program can't be known before execution i.e. only during run-time it can be decided that which form will be used.

Я надеюсь, что он немного почист.

Ответ 4

Перегрузка в этом отношении означает, что тип функции статически определяется во время компиляции, а не динамической отправки.

Что действительно происходит за кулисами, так это то, что для метода с именем "foo" с типами "A" и "B" создаются два метода ( "foo_A" и "foo_B" ). Какой из них должен вызываться, определяется во время компиляции (foo((A) object) или foo((B) object) приводит к вызову foo_A или foo_B). Таким образом, это полиморфизм времени компиляции, хотя реальный метод (т.е. Реализация в иерархии классов) определяется во время выполнения.

Ответ 5

Я категорически не согласен с перегрузкой метода вызова как с полиморфизмом времени компиляции.
Я согласен, что перегрузка метода - это статическое связывание (время компиляции), но я не видел в этом полиморфизма.

Я попытался выразить свое мнение в своем вопросе, чтобы получить разъяснения. Вы можете ссылаться на эту ссылку.