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

В терминах Java, когда кто-то спрашивает:

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

Может ли приемлемый ответ перегрузка или переопределять?

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

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

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

Ответ 1

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

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
...

Ответ 2

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

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

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

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

Ответ 5

Фактически оба используются для достижения полиморфизма.

  • У вас может быть метод в классе это переопределенный в одном или больше подклассов. Этот метод разные вещи, в зависимости от которых класс был использован для создания объекта.

    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);
        }
    }
    

Ответ 6

Вы правы, что перегрузка - это не ответ.

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

Ответ 7

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

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

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

Ответ 8

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

Вызывающий код не должен знать, каково конкретное животное.

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

Ответ 9

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

Ответ 10

Ни:

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

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

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

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

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

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

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

Если вы перегрузили, у вас будет:

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

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

Ответ 11

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

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

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

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

Ответ 12

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

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

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

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

Ответ 13

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

Из java tutorial

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

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

Относительно вашего второго запроса:

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

Его следует назвать переопределяющим.

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

  • Базовый класс не обеспечивает реализацию, а подкласс должен переопределить полный метод - (аннотация)
  • Базовый класс обеспечивает реализацию по умолчанию, а подкласс может изменять поведение
  • Подкласс добавляет расширение к реализации базового класса, вызывая super.methodName() как первый оператор
  • Базовый класс определяет структуру алгоритма (метод 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:

Ответ 14

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

Ответ 15

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

  class Vehicle{  
      void run()
          {
           System.out.println("Vehicle is running");
          }  
               }
   class Bike2 extends Vehicle{  
       void run()
           {
            System.out.println("Bike is running safely");
           }  

    public static void main(String args[]){  
    Bike2 obj = new Bike2();  
    obj.run();  
     }  

Выход: Велосипед работает безопасно........ Чтобы лучше понять переопределение, http://javabyroopam.blogspot.in/

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

   class Calculation{  
      void sum(int a,int b){System.out.println(a+b);}  
      void sum(int a,int b,int c){System.out.println(a+b+c);}  

      public static void main(String args[]){  
      Calculation obj=new Calculation();  
      obj.sum(10,10,10);  
       obj.sum(20,20);  

       }  
    }  

вывод 30,20

Ответ 16

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

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

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

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

Ответ 17

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

  • Поздняя привязка
  • Наследование.

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

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

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

Ответ 18

Полиморфизм более вероятен, поскольку он имеет значение... для ПЕРЕКРЫТИЯ в java

Все о различном поведении объекта SAME в разных ситуациях (при программировании... вы можете называть разные АРГУМЕНТЫ)

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

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

Но если мы изменим ARGUMENT... ПОВЕДЕНИЕ будет изменено...

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

Человек (здесь "Объект" ) тот же...

Ответ 19

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

Ответ 20

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

в любом случае, разница между этими двумя терминами лучше объясняется с использованием других языков, таких как С++: полиморфный объект в С++ ведет себя как 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 = новая собака();   собака b = новая собака();

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

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

Ответ 21

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());

    }
}