Полиморфизм против переопределения против перегрузки

347

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

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

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

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

Если у вас есть абстрактный базовый класс, который определил метод без реализации, и вы определили этот метод в подклассе, это все еще переопределяет?

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

Брайан Дж.
источник
Ниже приведены ответы, которые очень хорошо объясняют полиморфизм. Но у меня есть сильное возражение, чтобы сказать, что перегрузка - это тип полиморфизма, который я пытался обосновать в своем вопросе и ответе, который на самом деле концентрируется на перегрузке, полиморфизм или нет. Я пытался оправдать ответ @The Digital Gabeg, присутствующий в этой теме. См. Разработка: Перегрузка метода является статической привязкой / временем компиляции, но не полиморфизмом. Правильно ли соотносить статическое связывание с полиморфизмом?
ПравинКумар Лаласанги

Ответы:

894

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

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

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

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

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
...
Крис Кадмор
источник
37
@yuudachi. Я придумал этот пример при обучении в классе. Канонический класс «Банковский счет» на самом деле не выражал «абстрактность» базового класса. Другой канонический пример («Животное, шуметь») был слишком абстрактным для понимания. Я искал единственную базу со слишком очевидными подклассами. На самом деле, goPee () был единственным примером, который я придумал, который не был сексистским или стереотипным. (хотя в классе я печатал «по коридору слева» вместо того, чтобы вставать или садиться.)
Крис Кадмор
100
Этот пример также хорошо подчеркивает сложность использования иерархической системы для описания биологических систем. Некоторые люди, такие как совсем молодые, писают практически в любом положении - и младенцам нелегко сказать goPee (). Некоторые люди являются интерсексами, где биологические метки «мужской» или «женский» становятся довольно плохо определенными; социальные значения еще более сложны. В качестве учебного примера он показывает, как предположения моделирования могут иметь отрицательные результаты, например, подразумевает, что кто-то (например, студент по программированию ОО), страдающий недержанием или интерсекс, на самом деле не человек.
Эндрю Далке
7
Я могу вспомнить хотя бы горстку людей, которые опровергнут твой тезис «ты не можешь создать человека, который не является ни мужчиной, ни женщиной», хотя это все равно будет справедливо в отношении твоего кода ... плохая абстракция, полагаю, я говорю ? ;)
Фрэнк У. Замметти
2
Я думаю, важно отметить, что это только полиморфизм, потому что какую версию goPee () вызывать можно определить только во время выполнения. Хотя этот пример подразумевает это, приятно указать, почему именно это полиморфизм. Кроме того, это не требует родных классов. Это могут быть и отношения родитель-ребенок. Или даже совершенно не связанные классы, которые по совпадению имеют одинаковую функцию. Примером этого может быть функция .toString (). Который может быть вызван случайным образом для любого объекта, но компилятор никогда не может точно знать, какой тип объекта.
Тор Валамо
20
@AndrewDalke, +1 за заметки о биологической сложности. Кроме того, goPeeне принимает гравитационное поле в качестве входа. Эта зависимость от глобального состояния усложняет юнит-тестирование CatheterizedIntersexAstronautи показывает, что подклассы не всегда могут быть лучшим методом для составления признаков.
Майк Самуэль
99

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

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

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

Цифровой Габег
источник
8
Это старый, но полиморфизм не подразумевает, что другой класс должен быть в дереве наследования. Это происходит в Java, если вы считаете, что интерфейсы являются частью дерева наследования, но не в Go, где интерфейсы реализованы неявно.
JN
5
На самом деле, вам не нужны классы для полиморфизма вообще.
StCredZero
3
Я новичок, и поправьте меня, если я ошибаюсь, но я бы не сказал, что перегрузка не связана с полиморфизмом. По крайней мере в Java полиморфизм - это когда реализация выбирается в зависимости от типа вызывающего, а перегрузка - это когда реализация выбирается в зависимости от типа параметров, не так ли? Видя сходство между ними, я понимаю это.
csjacobs24
9
Неправильно. Ad hoc polymorphismявляется то , что вы описали в вашем перегружать разделе и является случай полиморфизма.
Джосси Кальдерон
1
«Это не связано ни с переопределением, ни с полиморфизмом». Это утверждение неверно.
Шайлеш Пратапвар
46

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

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

  1. Переопределение метода
  2. Перегрузка метода

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

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

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

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

Манодж
источник
5
+1 за хороший ответ. Принятый ответ объясняет только один тип полиморфизма. Этот ответ завершен.
Ападана
1
полиморфизм - это парадигма (ООП), но переопределение и перегрузка - это языковые возможности.
威 其 威
Полиморфизм также может быть достигнут универсальным типом.
Minh Nghĩa
43

Вот пример полиморфизма в псевдо-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 ().

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

Марк А. Николози
источник
Это пример полиморфизма во время выполнения. Полиморфизм времени компиляции также возможен через перегрузку методов и универсальные типы.
Пит Киркхем
Форма -> Параллелограмм -> Прямоугольник -> Квадрат
mpen
@ yankee2905 в этом случае, я думаю, вы могли бы использовать интерфейсы, поскольку класс может реализовывать несколько интерфейсов.
Sam003
1
@Zhisheng Или добавление метода pee в абстрактный родительский класс? Я бы использовал интерфейс для реализации чего-то еще.
Джои Рохан
43

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

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

    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);
        }
    }
Патрик МакЭлхани
источник
Я предполагаю, что это было отклонено, потому что исторически перегрузка метода не рассматривалась как часть полиморфизма в объектно-ориентированной парадигме. Перегрузка методов и полиморфизм - это две ортогональные, независимые особенности языка программирования.
Серхио Акоста
7
Как я сказал в своем ответе здесь, я не согласен - эти две особенности не ортогональны, но тесно связаны. Полиморфизм! = Наследование. У тебя есть мой голос.
Питер Мейер
2
Другими словами, тип полиморфизм против специального полиморфизма. Я поддерживаю этот ответ, даже если он не настолько полный, как следовало бы, потому что он правильно утверждает, что как перегрузка, так и переопределение связаны с полиморфизмом. Сказать, что полиморфизм в языках ООП может быть достигнут только с помощью наследования классов, просто неправильно - мы должны помнить, что есть некоторые другие языки ООП, кроме Java и C ++, где можно использовать такие понятия, как множественная диспетчеризация, специальный полиморфизм, параметрический полиморфизм и т. Д. ,
Ренна
2
@rsenna Это может быть неполным, но это отвечает на вопрос гораздо лучше, чем остальные ИМХО. Также очень приятно, что вы упомянули специальный и параметрический полиморфизм.
Валентин Раду
15

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

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

Алекс Б
источник
3
Изменяется не поведение объекта, а его реализация. Такое же поведение, другая реализация, это полиморфизм.
QBziZ
@QBziZ Вам нужно определить поведение , особенно прилагательное же . Если поведение такое же, почему их реализация должна быть другой? Дело не в том, что кто-то недоволен определенной реализацией, поэтому требует другой.
Snađошƒаӽ
11

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

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

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

Питер Мейер
источник
Вы правы в том, что означают эти слова в целом, но в контексте программирования, когда люди говорят «полиморфизм», они всегда означают «полиморфизм на основе наследования». Интересный момент, но я думаю, что описание полиморфизма таким образом смущает людей.
Цифровой Gabeg
Может быть, проще объяснить полиморфизм только с точки зрения наследования, но, как этот конкретный вопрос был задан, я думаю, что было бы целесообразно также описать параметрический полиморфизм.
Патрик МакЭлхани
4
Чтобы быть ясным, я думаю, что должны быть изложены различные формы - что я даже не сделал адекватно - потому что здесь есть несколько ответов, которые представлены как абсолютные. Я с уважением не согласен с тем, что в «контексте программирования ...« полиморфизм »всегда означает« полиморфизм, основанный на наследовании »»
Питер Мейер
2
я думаю, что перегрузка лучше классифицировать как Ad-hoc_polymorphism en.wikipedia.org/wiki/…
Manu
Я склонен согласиться с «The Digital Gabeg» в следующем. Если вы обсуждаете ООП, полиморфизм обычно означает полиморфизм подтипа, а если вы обсуждаете теорию типов, это означает любой тип полиморфизма. Но, как вы говорите, с «контекстом программиста» его слишком двусмысленно выводить.
Ману,
7

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

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

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

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

BillC
источник
2
Определенно лучший ответ пока. Полиморфизм может применяться ко всем языковым конструкциям, будь то существительные (классы) или глаголы (методы).
Раду Гаслер
6

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

Код вызова не должен знать, что это за конкретное животное.

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

Брайан Дж.
источник
4

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

MXG
источник
4

Ни:

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

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

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

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

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

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

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

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

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

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

jpeacock
источник
4

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

Почему полиморфизм так важен в любом языке ООП.

Давайте попробуем создать простое приложение для телевизора с наследованием / полиморфизмом и без него. Размещая каждую версию приложения, мы делаем небольшую ретроспективу.

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

Вы начинаете с написания классов для каждой из этих функций, добавляя

  1. set: - для установки значения контроллера. (Предположим, что для этого есть специальный код контроллера)
  2. get: - Чтобы получить значение контроллера. (Предположим, это имеет специальный код контроллера)
  3. настроить: - Для проверки ввода и настройки контроллера. (Общие проверки .. независимо от контроллеров)
  4. Отображение пользовательского ввода с контроллерами: - Чтобы получить пользовательский ввод и соответственно вызывать контроллеры.

Версия приложения 1

import java.util.Scanner;    
class VolumeControllerV1 {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class  BrightnessControllerV1 {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class ColourControllerV1    {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

/*
 *       There can be n number of controllers
 * */
public class TvApplicationV1 {
    public static void main(String[] args)  {
        VolumeControllerV1 volumeControllerV1 = new VolumeControllerV1();
        BrightnessControllerV1 brightnessControllerV1 = new BrightnessControllerV1();
        ColourControllerV1 colourControllerV1 = new ColourControllerV1();


        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println("Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV1.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV1.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV1.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV1.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV1.adjust(5);
                    break;
                }
                case 6: {
                colourControllerV1.adjust(-5);
                break;
            }
            default:
                System.out.println("Shutting down...........");
                break OUTER;
        }

    }
    }
}

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

Проблемы в ТВ-версии приложения 1

  1. Код Adjust (int value) повторяется во всех трех классах. Вы хотели бы минимизировать дублирование кода. (Но вы не думали об общем коде и перемещении его в какой-то суперкласс, чтобы избежать дублирования кода)

Вы решаете жить с этим, пока ваше приложение работает, как ожидалось.

Через некоторое время ваш босс возвращается к вам и просит добавить функцию сброса в существующее приложение. Сброс установит все три контроллера на их соответствующие значения по умолчанию.

Вы начинаете писать новый класс (ResetFunctionV2) для новой функциональности и сопоставляете код отображения пользовательского ввода для этой новой функции.

Версия приложения 2

import java.util.Scanner;
class VolumeControllerV2    {

    private int defaultValue = 25;
    private int value;

    int getDefaultValue() {
        return defaultValue;
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class  BrightnessControllerV2   {

    private int defaultValue = 50;
    private int value;
    int get()    {
        return value;
    }
    int getDefaultValue() {
        return defaultValue;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class ColourControllerV2    {

    private int defaultValue = 40;
    private int value;
    int get()    {
        return value;
    }
    int getDefaultValue() {
        return defaultValue;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

class ResetFunctionV2 {

    private VolumeControllerV2 volumeControllerV2 ;
    private BrightnessControllerV2 brightnessControllerV2;
    private ColourControllerV2 colourControllerV2;

    ResetFunctionV2(VolumeControllerV2 volumeControllerV2, BrightnessControllerV2 brightnessControllerV2, ColourControllerV2 colourControllerV2)  {
        this.volumeControllerV2 = volumeControllerV2;
        this.brightnessControllerV2 = brightnessControllerV2;
        this.colourControllerV2 = colourControllerV2;
    }
    void onReset()    {
        volumeControllerV2.set(volumeControllerV2.getDefaultValue());
        brightnessControllerV2.set(brightnessControllerV2.getDefaultValue());
        colourControllerV2.set(colourControllerV2.getDefaultValue());
    }
}
/*
 *       so on
 *       There can be n number of controllers
 *
 * */
public class TvApplicationV2 {
    public static void main(String[] args)  {
        VolumeControllerV2 volumeControllerV2 = new VolumeControllerV2();
        BrightnessControllerV2 brightnessControllerV2 = new BrightnessControllerV2();
        ColourControllerV2 colourControllerV2 = new ColourControllerV2();

        ResetFunctionV2 resetFunctionV2 = new ResetFunctionV2(volumeControllerV2, brightnessControllerV2, colourControllerV2);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV2.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV2.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV2.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV2.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV2.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV2.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV2.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Итак, ваше приложение готово с функцией сброса. Но теперь вы начинаете понимать, что

Проблемы в телевизионном приложении версии 2

  1. Если новый продукт введен в продукт, вы должны изменить код функции сброса.
  2. Если количество контроллеров растет очень высоко, у вас возникнет проблема с удержанием ссылок контроллеров.
  3. Сброс кода функции тесно связан со всем кодом класса контроллеров (для получения и установки значений по умолчанию).
  4. Сбросить класс объектов (ResetFunctionV2) может получить доступ к другому методу класса Controller (настроить), что нежелательно.

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

Теперь вы начинаете думать, что эта новая функция, которая будет добавлена, напоминает функцию «Сброс», и «Проблемы приложения» (V2) будут умножены, если вы не пересчитаете свое приложение.

Вы начинаете думать об использовании наследования, чтобы воспользоваться преимуществами полиморфной способности JAVA, и добавляете новый абстрактный класс (ControllerV3) в

  1. Объявите подпись метода get и set.
  2. Содержит настройку реализации метода, которая ранее была реплицирована среди всех контроллеров.
  3. Объявите метод setDefault, чтобы можно было легко реализовать функцию сброса, используя полиморфизм.

Благодаря этим улучшениям у вас есть готовая версия 3 вашего телевизионного приложения.

Версия приложения 3

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

abstract class ControllerV3 {
    abstract void set(int value);
    abstract int get();
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
    abstract void setDefault();
}
class VolumeControllerV3 extends ControllerV3   {

    private int defaultValue = 25;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
}
class  BrightnessControllerV3  extends ControllerV3   {

    private int defaultValue = 50;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
}
class ColourControllerV3 extends ControllerV3   {

    private int defaultValue = 40;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
}

class ResetFunctionV3 {

    private List<ControllerV3> controllers = null;

    ResetFunctionV3(List<ControllerV3> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (ControllerV3 controllerV3 :this.controllers)  {
            controllerV3.setDefault();
        }
    }
}
/*
 *       so on
 *       There can be n number of controllers
 *
 * */
public class TvApplicationV3 {
    public static void main(String[] args)  {
        VolumeControllerV3 volumeControllerV3 = new VolumeControllerV3();
        BrightnessControllerV3 brightnessControllerV3 = new BrightnessControllerV3();
        ColourControllerV3 colourControllerV3 = new ColourControllerV3();

        List<ControllerV3> controllerV3s = new ArrayList<>();
        controllerV3s.add(volumeControllerV3);
        controllerV3s.add(brightnessControllerV3);
        controllerV3s.add(colourControllerV3);

        ResetFunctionV3 resetFunctionV3 = new ResetFunctionV3(controllerV3s);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV3.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV3.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV3.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV3.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV3.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV3.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV3.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Хотя большинство проблем, перечисленных в списке проблем V2, были решены, за исключением

Проблемы в ТВ-версии приложения 3

  1. Сброс класса объектов (ResetFunctionV3) может получить доступ к другому методу класса Controller (настроить), что нежелательно.

Опять же, вы думаете о решении этой проблемы, так как теперь у вас есть еще одна функция (обновление драйвера при запуске), которая также будет реализована. Если вы не исправите это, он также будет перенесен на новые функции.

Таким образом, вы разделяете контракт, определенный в абстрактном классе, и пишете 2 интерфейса для

  1. Сбросить функцию.
  2. Обновление драйвера.

И пусть ваш первый конкретный класс реализует их, как показано ниже

Версия приложения 4

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

interface OnReset {
    void setDefault();
}
interface OnStart {
    void checkForDriverUpdate();
}
abstract class ControllerV4 implements OnReset,OnStart {
    abstract void set(int value);
    abstract int get();
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

class VolumeControllerV4 extends ControllerV4 {

    private int defaultValue = 25;
    private int value;
    @Override
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for VolumeController .... Done");
    }
}
class  BrightnessControllerV4 extends ControllerV4 {

    private int defaultValue = 50;
    private int value;
    @Override
    int get()    {
        return value;
    }
    @Override
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }

    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for BrightnessController .... Done");
    }
}
class ColourControllerV4 extends ControllerV4 {

    private int defaultValue = 40;
    private int value;
    @Override
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for ColourController .... Done");
    }
}
class ResetFunctionV4 {

    private List<OnReset> controllers = null;

    ResetFunctionV4(List<OnReset> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (OnReset onreset :this.controllers)  {
            onreset.setDefault();
        }
    }
}
class InitializeDeviceV4 {

    private List<OnStart> controllers = null;

    InitializeDeviceV4(List<OnStart> controllers)  {
        this.controllers = controllers;
    }
    void initialize()    {
        for (OnStart onStart :this.controllers)  {
            onStart.checkForDriverUpdate();
        }
    }
}
/*
*       so on
*       There can be n number of controllers
*
* */
public class TvApplicationV4 {
    public static void main(String[] args)  {
        VolumeControllerV4 volumeControllerV4 = new VolumeControllerV4();
        BrightnessControllerV4 brightnessControllerV4 = new BrightnessControllerV4();
        ColourControllerV4 colourControllerV4 = new ColourControllerV4();
        List<ControllerV4> controllerV4s = new ArrayList<>();
        controllerV4s.add(brightnessControllerV4);
        controllerV4s.add(volumeControllerV4);
        controllerV4s.add(colourControllerV4);

        List<OnStart> controllersToInitialize = new ArrayList<>();
        controllersToInitialize.addAll(controllerV4s);
        InitializeDeviceV4 initializeDeviceV4 = new InitializeDeviceV4(controllersToInitialize);
        initializeDeviceV4.initialize();

        List<OnReset> controllersToReset = new ArrayList<>();
        controllersToReset.addAll(controllerV4s);
        ResetFunctionV4 resetFunctionV4 = new ResetFunctionV4(controllersToReset);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV4.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV4.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV4.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV4.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV4.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV4.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV4.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Теперь все проблемы, с которыми вы столкнулись, были решены, и вы поняли, что с помощью наследования и полиморфизма вы можете

  1. Сохраняйте слабую связь между различными частями приложения. (Компонентам функции «Сброс» или «Обновление драйвера» не нужно знать о фактических классах контроллера (Громкость, Яркость и Цвет)), любой класс, реализующий OnReset или OnStart, будет приемлем для функции «Сброс» или «Обновление драйвера». компоненты соответственно).
  2. Улучшение приложения становится проще (новое добавление контроллера не влияет на сброс или компонент обновления драйверов, и теперь вам действительно легко добавлять новые)
  3. Сохраняйте уровень абстракции. (Теперь функция Reset может видеть только метод контроллеров setDefault, а функция Reset может видеть только метод контроллеров checkForDriverUpdate)

Надеюсь это поможет :-)

разработчик
источник
3

Термин «перегрузка» означает наличие нескольких версий одного и того же имени, обычно это методы с разными списками параметров.

public int DoSomething(int objectId) { ... }
public int DoSomething(string objectName) { ... }

Таким образом, эти функции могут делать то же самое, но у вас есть возможность вызвать его с помощью идентификатора или имени. Не имеет ничего общего с наследованием, абстрактными классами и т. Д.

Переопределение обычно относится к полиморфизму, как вы описали в своем вопросе

Клайд
источник
2

перегрузка - это когда вы определяете 2 метода с одинаковым именем, но разными параметрами

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

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

Однако, если бы кто-то дал мне простой ответ «переопределения» на вопрос «Что такое полиморфизм?» Я бы попросил дальнейших объяснений.

Matt
источник
2

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

Genjuro
источник
2

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

Из Java- учебник

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

Рассматривая примеры и определения, следует переопределить ответ.

По поводу вашего второго запроса:

Если у вас есть абстрактный базовый класс, который определил метод без реализации, и вы определили этот метод в подклассе, это все еще переопределяет?

Это следует назвать переопределением.

Посмотрите на этот пример, чтобы понять различные типы переопределения.

  1. Базовый класс не обеспечивает реализацию, а подкласс должен переопределять полный метод - (аннотация)
  2. Базовый класс обеспечивает реализацию по умолчанию, а подкласс может изменить поведение
  3. Подкласс добавляет расширение к реализации базового класса, вызывая super.methodName()первый оператор
  4. Базовый класс определяет структуру алгоритма (метод Template), а подкласс переопределяет часть алгоритма

фрагмент кода:

import java.util.HashMap;

abstract class Game implements Runnable{

    protected boolean runGame = true;
    protected Player player1 = null;
    protected Player player2 = null;
    protected Player currentPlayer = null;

    public Game(){
        player1 = new Player("Player 1");
        player2 = new Player("Player 2");
        currentPlayer = player1;
        initializeGame();
    }

    /* Type 1: Let subclass define own implementation. Base class defines abstract method to force
        sub-classes to define implementation    
    */

    protected abstract void initializeGame();

    /* Type 2: Sub-class can change the behaviour. If not, base class behaviour is applicable */
    protected void logTimeBetweenMoves(Player player){
        System.out.println("Base class: Move Duration: player.PlayerActTime - player.MoveShownTime");
    }

    /* Type 3: Base class provides implementation. Sub-class can enhance base class implementation by calling
        super.methodName() in first line of the child class method and specific implementation later */
    protected void logGameStatistics(){
        System.out.println("Base class: logGameStatistics:");
    }
    /* Type 4: Template method: Structure of base class can't be changed but sub-class can some part of behaviour */
    protected void runGame() throws Exception{
        System.out.println("Base class: Defining the flow for Game:");  
        while ( runGame) {
            /*
            1. Set current player
            2. Get Player Move
            */
            validatePlayerMove(currentPlayer);  
            logTimeBetweenMoves(currentPlayer);
            Thread.sleep(500);
            setNextPlayer();
        }
        logGameStatistics();
    }
    /* sub-part of the template method, which define child class behaviour */
    protected abstract void validatePlayerMove(Player p);

    protected void setRunGame(boolean status){
        this.runGame = status;
    }
    public void setCurrentPlayer(Player p){
        this.currentPlayer = p;
    }
    public void setNextPlayer(){
        if ( currentPlayer == player1) {
            currentPlayer = player2;
        }else{
            currentPlayer = player1;
        }
    }
    public void run(){
        try{
            runGame();
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

class Player{
    String name;
    Player(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
}

/* Concrete Game implementation  */
class Chess extends Game{
    public Chess(){
        super();
    }
    public void initializeGame(){
        System.out.println("Child class: Initialized Chess game");
    }
    protected void validatePlayerMove(Player p){
        System.out.println("Child class: Validate Chess move:"+p.getName());
    }
    protected void logGameStatistics(){
        super.logGameStatistics();
        System.out.println("Child class: Add Chess specific logGameStatistics:");
    }
}
class TicTacToe extends Game{
    public TicTacToe(){
        super();
    }
    public void initializeGame(){
        System.out.println("Child class: Initialized TicTacToe game");
    }
    protected void validatePlayerMove(Player p){
        System.out.println("Child class: Validate TicTacToe move:"+p.getName());
    }
}

public class Polymorphism{
    public static void main(String args[]){
        try{

            Game game = new Chess();
            Thread t1 = new Thread(game);
            t1.start();
            Thread.sleep(1000);
            game.setRunGame(false);
            Thread.sleep(1000);

            game = new TicTacToe();
            Thread t2 = new Thread(game);
            t2.start();
            Thread.sleep(1000);
            game.setRunGame(false);

        }catch(Exception err){
            err.printStackTrace();
        }       
    }
}

вывод:

Child class: Initialized Chess game
Base class: Defining the flow for Game:
Child class: Validate Chess move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate Chess move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
Child class: Add Chess specific logGameStatistics:
Child class: Initialized TicTacToe game
Base class: Defining the flow for Game:
Child class: Validate TicTacToe move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate TicTacToe move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
Равиндра Бабу
источник
2

Я думаю, ребята, вы смешиваете понятия. Полиморфизм - это способность объекта вести себя по-разному во время выполнения. Для достижения этого вам необходимо два условия:

  1. Позднее связывание
  2. Наследование.

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

Однако в C ++ это не так. Любой перегруженный метод, независимо от того, является ли подпись одинаковой или нет (разная сумма, другой тип), также переопределяется . То есть сегодня метод базового класса больше не доступен в подклассе, когда он вызывается извне объекта подкласса, очевидно.

Таким образом, ответ на вопрос о перегрузке использования Java . В любом другом языке может отличаться, как это происходит в C ++

user1154840
источник
1

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

Все дело в разном поведении одного и того же объекта в разных ситуациях (в программировании ... вы можете вызывать разные аргументы)

Я думаю, что пример ниже поможет вам понять ... Хотя это не чистый код Java ...

     public void See(Friend)
     {
        System.out.println("Talk");
     }

Но если мы изменим АРГУМЕНТ ... ПОВЕДЕНИЕ будет изменено ...

     public void See(Enemy)
     {
        System.out.println("Run");
     }

Человек (здесь «Объект») такой же ...

Rajan
источник
1

Полиморфизм - это множественные реализации объекта, или вы можете сказать несколько форм объекта. Допустим, у вас есть класс Animalsв качестве абстрактного базового класса, и у него есть метод, movement()который определяет способ перемещения животного. Теперь в действительности у нас есть разные виды животных, и они двигаются по-разному, а некоторые из них с двумя ногами, другие с четырьмя, а некоторые без ног и т. Д. Чтобы определить разные виды movement()животных на земле, нам нужно применить полиморфизм. Однако вам нужно определить больше классов, то есть класса Dogs Cats Fishи т. Д. Затем вам нужно расширить эти классы из базового класса Animalsи переопределить его метод movement()новыми функциональными возможностями движения, основанными на каждом имеющемся у вас животном. Вы также можете использоватьInterfacesчтобы достичь этого. Ключевое слово здесь переопределено, перегрузка отличается и не рассматривается как полиморфизм. с перегрузкой вы можете определить несколько методов «с одинаковым именем», но с разными параметрами для одного и того же объекта или класса.

Солид Снейк
источник
0

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

в любом случае разницу между этими двумя терминами лучше объяснить с помощью других языков, таких как c ++: полиморфный объект в c ++ ведет себя как java-аналог, если базовая функция виртуальная, но если метод не виртуальный, переход кода разрешается статически , и истинный тип не проверяется во время выполнения, поэтому полиморфизм включает способность объекта вести себя по-разному в зависимости от интерфейса, используемого для доступа к нему; позвольте мне привести пример в псевдокоде:

class animal {
    public void makeRumor(){
        print("thump");
    }
}
class dog extends animal {
    public void makeRumor(){
        print("woff");
    }
}

animal a = new dog();
dog b = new dog();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

(предположим, что makeRumor НЕ является виртуальным)

Java действительно не предлагает этот уровень полиморфизма (называемый также разрезанием объектов).

животное а = новая собака (); собака б = новая собака ();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

в обоих случаях он будет печатать только woff. Так как a и b ссылаются на классную собаку

Лоренцо Боккачча
источник
некоторые ссылки: linuxtopia.org/online_books/programming_books/thinking_in_c++/…
Лоренцо
животное а = новая собака (); a был построен как собака, и будет печатать "woff". Если вы хотите, чтобы он печатал «thump», то вам нужно его выгнать. ((Animal) a) .makeRumor ()
Крис Кадмор
Это референц-апскейтинг, но объект все еще собака. Если вы хотите, чтобы это было животное, вы должны явно выгнать объект.
Крис Кадмор
Догадаться. Вопрос был помечен Java. Вы ответили на C ++. Вы можете быть правы в C ++. Я определенно прав в Java.
Крис Кадмор
должно происходить каждый раз, когда задействован конструктор копирования, ссылка fredosaurus.com/notes-cpp/oop-condestructors/… case three соответствует; игнорировать новый оператор, который существует только для устранения неоднозначности создания.
Лоренцо Боккачча
0
import java.io.IOException;

class Super {

    protected Super getClassName(Super s) throws IOException {
        System.out.println(this.getClass().getSimpleName() + " - I'm parent");
        return null;
    }

}

class SubOne extends Super {

    @Override
    protected Super getClassName(Super s)  {
        System.out.println(this.getClass().getSimpleName() + " - I'm Perfect Overriding");
        return null;
    }

}

class SubTwo extends Super {

    @Override
    protected Super getClassName(Super s) throws NullPointerException {
        System.out.println(this.getClass().getSimpleName() + " - I'm Overriding and Throwing Runtime Exception");
        return null;
    }

}

class SubThree extends Super {

    @Override
    protected SubThree getClassName(Super s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Returning SubClass Type");
        return null;
    }

}

class SubFour extends Super {

    @Override
    protected Super getClassName(Super s) throws IOException {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Throwing Narrower Exception ");
        return null;
    }

}

class SubFive extends Super {

    @Override
    public Super getClassName(Super s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and have broader Access ");
        return null;
    }

}

class SubSix extends Super {

    public Super getClassName(Super s, String ol) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading ");
        return null;
    }

}

class SubSeven extends Super {

    public Super getClassName(SubSeven s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading because Method signature (Argument) changed.");
        return null;
    }

}

public class Test{

    public static void main(String[] args) throws Exception {

        System.out.println("Overriding\n");

        Super s1 = new SubOne(); s1.getClassName(null);

        Super s2 = new SubTwo(); s2.getClassName(null);

        Super s3 = new SubThree(); s3.getClassName(null);

        Super s4 = new SubFour(); s4.getClassName(null);

        Super s5 = new SubFive(); s5.getClassName(null);

        System.out.println("Overloading\n");

        SubSix s6 = new SubSix(); s6.getClassName(null, null);

        s6 = new SubSix(); s6.getClassName(null);

        SubSeven s7 = new SubSeven(); s7.getClassName(s7);

        s7 = new SubSeven(); s7.getClassName(new Super());

    }
}
bharanitharan
источник