Полиморфизм против переопределения против перегрузки - PullRequest
327 голосов
/ 30 сентября 2008

С точки зрения Java, когда кто-то спрашивает:

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

Будет ли перегрузка или переопределением приемлемым ответом?

Я думаю, в этом есть нечто большее.

ЕСЛИ у вас был абстрактный базовый класс, который определил метод без реализации, и вы определили этот метод в подклассе, он все еще переопределяется? Я думаю, перегрузка - это не правильный ответ.

Ответы [ 21 ]

871 голосов
/ 01 октября 2008

Самый простой способ выразить полиморфизм - это абстрактный базовый класс (или интерфейс)

public abstract class Human{
   ...
   public abstract void goPee();
}

Этот класс является абстрактным, потому что метод goPee() не определим для людей. Это определимо только для подклассов мужского и женского пола. Кроме того, человек - это абстрактное понятие & mdash; Вы не можете создать человека, который не является ни мужчиной, ни женщиной. Это должен быть один или другой.

Таким образом, мы откладываем реализацию, используя абстрактный класс.

public class Male extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Stand Up");
    }
}

и

public class Female extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Sit Down");
    }
}

Теперь мы можем сказать целой комнате, полной людей, чтобы пописать.

public static void main(String[] args){
    ArrayList<Human> group = new ArrayList<Human>();
    group.add(new Male());
    group.add(new Female());
    // ... add more...

    // tell the class to take a pee break
    for (Human person : group) person.goPee();
}

Выполнение этого приведет к:

Stand Up
Sit Down
...
91 голосов
/ 30 сентября 2008

Полиморфизм - это способность экземпляра класса вести себя так, как если бы он был экземпляром другого класса в своем дереве наследования, чаще всего одним из его классов-предков. Например, в Java все классы наследуются от Object. Следовательно, вы можете создать переменную типа Object и присвоить ей экземпляр любого класса.

override - это тип функции, которая встречается в классе, который наследуется от другого класса. Функция переопределения «заменяет» функцию, унаследованную от базового класса, но делает это таким образом, что она вызывается, даже когда экземпляр ее класса притворяется, что это другой тип посредством полиморфизма. Ссылаясь на предыдущий пример, вы можете определить свой собственный класс и переопределить функцию toString (). Поскольку эта функция унаследована от Object, она все равно будет доступна, если вы скопируете экземпляр этого класса в переменную Object-type. Обычно, если вы вызываете toString () в своем классе, когда он притворяется объектом Object, то версия toString, которая на самом деле будет вызывать это та, которая определена для самого Object. Однако, поскольку функция является переопределением, определение toString () из вашего класса используется, даже когда истинный тип экземпляра класса скрыт за полиморфизмом.

Перегрузка - это определение нескольких методов с одинаковыми именами, но с разными параметрами. Это не связано ни с переопределением, ни с полиморфизмом.

43 голосов
/ 30 сентября 2008

Вот пример полиморфизма в псевдо-C # / Java:

class Animal
{
    abstract string MakeNoise ();
}

class Cat : Animal {
    string MakeNoise () {
        return "Meow";
    }
}

class Dog : Animal {
    string MakeNoise () {
        return "Bark";
    }
}

Main () {
   Animal animal = Zoo.GetAnimal ();
   Console.WriteLine (animal.MakeNoise ());
}

Функция Main не знает тип животного и зависит от поведения конкретной реализации метода MakeNoise ().

Редактировать: Похоже, Брайан избил меня до удара. Забавно, мы использовали один и тот же пример. Но приведенный выше код должен помочь прояснить понятия.

43 голосов
/ 21 октября 2012

Полиморфизм означает более одной формы, один и тот же объект выполняет различные операции в соответствии с требованием.

Полиморфизм может быть достигнут двумя способами:

  1. Метод переопределения
  2. Метод перегрузки

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

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

В Java для достижения полиморфизма ссылочная переменная суперкласса может содержать объект подкласса.

Для достижения полиморфизма каждый разработчик должен использовать в проекте одинаковые имена методов.

39 голосов
/ 30 сентября 2008

Как переопределение, так и перегрузка используются для достижения полиморфизма.

Вы можете иметь метод в классе переопределено в одном или больше подклассов. Метод делает разные вещи, в зависимости от которых класс был использован для создания объекта.

    abstract class Beverage {
       boolean isAcceptableTemperature();
    }

    class Coffee extends Beverage {
       boolean isAcceptableTemperature() { 
           return temperature > 70;
       }
    }

    class Wine extends Beverage {
       boolean isAcceptableTemperature() { 
           return temperature < 10;
       }
    }

Вы также можете иметь метод, который перегружен с двумя или более наборами аргументов. Метод делает разные вещи, основанные на тип (ы) переданного аргумента (ов).

    class Server {
        public void pour (Coffee liquid) {
            new Cup().fillToTopWith(liquid);
        }

        public void pour (Wine liquid) {
            new WineGlass().fillHalfwayWith(liquid);
        }

        public void pour (Lemonade liquid, boolean ice) {
            Glass glass = new Glass();
            if (ice) {
                glass.fillToTopWith(new Ice());
            }
            glass.fillToTopWith(liquid);
        }
    }
13 голосов
/ 30 сентября 2008

Вы правы, что перегрузка не является ответом.

Ни один не переопределяет. Переопределение - это средство, с помощью которого вы получаете полиморфизм. Полиморфизм - это способность объекта изменять поведение в зависимости от его типа. Лучше всего это продемонстрировать, когда вызывающий объект, который проявляет полиморфизм, не знает, к какому типу относится этот объект.

10 голосов
/ 30 сентября 2008

Конкретное высказывание о перегрузке или переопределении не дает полной картины. Полиморфизм - это просто способность объекта специализировать свое поведение в зависимости от его типа.

Я бы не согласился с некоторыми ответами, заключающимися в том, что перегрузка является формой полиморфизма (параметрического полиморфизма) в том случае, если метод с одинаковым именем может вести себя по-разному, давая разные типы параметров. Хорошим примером является перегрузка операторов. Вы можете определить «+», чтобы принимать различные типы параметров - например, строки или целые числа - и на основе этих типов «+» будет вести себя по-разному.

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

7 голосов
/ 20 декабря 2010

Полиморфизм просто означает «много форм».

Это НЕ ТРЕБУЕТ наследования для достижения ... поскольку реализация интерфейса, которая вообще не является наследованием, служит полиморфным потребностям. Возможно, реализация интерфейса удовлетворяет полиморфные потребности «лучше», чем наследование.

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

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

6 голосов
/ 30 сентября 2008

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

В вызывающем коде не обязательно знать, что это за конкретное животное.

Это то, что я считаю полиморфизмом.

4 голосов
/ 30 сентября 2008

Ни:

Перегрузка - это когда у вас одно и то же имя функции, которое принимает разные параметры.

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

Полиморфизм позднего связывания, например, методы базового класса (родительского) вызываются, но только во время выполнения приложение узнает, что представляет собой фактический объект - это может быть дочерний класс, методы которого отличаются. Это связано с тем, что любой дочерний класс может использоваться там, где определен базовый класс.

В Java вы часто видите полиморфизм с библиотекой коллекций:

int countStuff(List stuff) {
  return stuff.size();
}

Список - это базовый класс, компилятор не имеет ни малейшего представления, если вы подсчитываете связанный список, вектор, массив или пользовательскую реализацию списка, если он действует как список:

List myStuff = new MyTotallyAwesomeList();
int result = countStuff(myStuff);

Если бы вы были перегружены, вы бы получили:

int countStuff(LinkedList stuff) {...}
int countStuff(ArrayList stuff) {...}
int countStuff(MyTotallyAwesomeList stuff) {...}
etc...

и правильная версия countStuff () будет выбрана компилятором для соответствия параметрам.

...