В чем основное различие между наследованием и полиморфизмом?

172

Сегодня мне поставили этот вопрос в конце экзамена по открытой книге модуля, и я потерял себя. Я читал, Head first Javaи оба определения казались абсолютно одинаковыми. Мне просто интересно, какова ГЛАВНАЯ разница для моего собственного разума. Я знаю, что есть ряд подобных вопросов, но ни один из них, которые я видел, не дает однозначного ответа.

Даррен Берджесс
источник

Ответы:

289

Наследование - это когда «класс» происходит от существующего «класса». Итак, если у вас есть Personкласс, то у вас есть Studentкласс, который расширяет Person, Student наследует все, что Personимеет. Есть некоторые подробности относительно модификаторов доступа, которые вы помещаете в поля / методы в Person, но это основная идея. Например, если у вас есть закрытое поле Person, Studentоно не будет отображаться, потому что его закрытые и закрытые поля не видны подклассам.

Полиморфизм имеет дело с тем, как программа решает, какие методы она должна использовать, в зависимости от того, что она имеет. Если у вас есть метод Person, у которого есть readметод, и у вас есть метод, Studentкоторый расширяет Person, который имеет свою собственную реализацию read, то какой метод вызывается, определяется для вас во время выполнения, в зависимости от того, есть ли у вас Personили Student. Это немного сложно, но если вы делаете что-то вроде

Person p = new Student();
p.read();

вызывается метод read для Student . Это полиморфизм в действии. Вы можете сделать это назначение, потому что a Student является a Person , но среда выполнения достаточно умна, чтобы знать, что фактическим типом pявляется Student .

Обратите внимание, что детали различаются для разных языков. Например, вы можете выполнять наследование в javascript, но оно совершенно отличается от того, как оно работает в Java.

hvgotcodes
источник
9
@ hvgtcodes Итак, в двух словах, отношение суперкласс-подкласс - это наследование, а концепция реализации одного и того же метода по-разному между родительским классом и его подклассами, а вызов их в зависимости от ситуации - полиморфизм. Я прав?
Мухаммед Райхан Мухаймин
1
@hvgotcodes , но говорят , что если Person«S readметод использует модификатор доступа общественности, не будут Studentобъекты быть в состоянии получить доступ к ним? и тогда Student s = new Student();не будет ли легче? Я все еще не совсем понимаю преимущества полиморфизма.
Scorpiorian83
1
@hvgotcodes Student s = new Student () будет работать. Но скажем, после того, как вы написали много кода, используя эту идею, и позже вы поймете, что допустили ошибку. Человек на самом деле не студент, это учитель. Таким образом, вы можете просто изменить Person p = new Student () на Person p = new Teacher (), тогда ваша жизнь станет намного проще.
munmunbb
Мой вопрос здесь, почему вы хотите использовать Person p = new Student();вместо Student p = new Student();?
PerfectContrast,
@PerfectContrast Я думаю, что это полезно, когда вы хотите, чтобы ученик, водитель, учитель и т. Д. Выступали в качестве лица, и вы группируете их в списке или чем-то еще. Поэтому, когда вы вызываете «read» для всех, каждый вызывает свой собственный метод «read».
Саванте
205

Наследование относится к использованию структуры и поведения суперкласса в подклассе.

Полиморфизм относится к изменению поведения суперкласса в подклассе.

Тед Хопп
источник
5
Означает ли этот ответ, что полиморфизм требует наследования?
jaco0646
6
@ jaco0646 - В контексте Java, я так думаю. (В других языках, возможно, не так много.) Обратите внимание, что «супер класс» и «подкласс» используются здесь свободно. Полиморфизм также может означать наследование поведения, указанного (но не реализованного) в интерфейсе.
Тед Хопп
1
@AlirezaRahmani - я не понимаю ваш комментарий. Вы имеете в виду, что наследование не включает наследование как свойств, так и поведения? Это противоречило бы тому, как Java (и большинство объектно-ориентированных языков на основе классов) определяет наследование. Из Спецификации языка Java, §8.4.8 : «Класс C наследует от своего прямого суперкласса все конкретные методы m(оба staticи instance) суперкласса, для которого ...» (с последующими подробностями о наследовании). Звучит как «повторное использование кода» для меня.
Тед Хопп
@TedHopp Inheritance - это, прежде всего, полиморфный инструмент, но некоторые люди, к более поздней опасности, пытаются использовать его как способ повторного использования / совместного использования кода. Смысл в том, что «хорошо, если я наследую, я получу все методы бесплатно», но игнорируя тот факт, что эти два класса потенциально не имеют полиморфных отношений.
Алиреза Рахмани Халили
1
@AlirezaRahmani - В Java (о чем конкретно спрашивает OP в соответствии с тегами) наследование классов наиболее определенно включает наследование поведения. Это часть определения языка. Тот факт, что это может быть неправильно использовано при описании, является одной из слабых сторон Java. (Связанный недостаток заключался в объявлении классов для реализации интерфейсов просто для импорта констант, определенных в интерфейсе. В конце концов, разработчики Java представили, import staticчтобы устранить это неправильное использование интерфейсов.) Для чистого полиморфизма в Java, инструмент, который нужно использовать, это интерфейсы, а не наследование классов.
Тед Хопп
63

Полиморфизм : способность одинаково относиться к объектам разных типов. Пример: Жираф и Крокодил - это и животные, и животные могут Move. Если у вас есть экземпляр, Animalвы можете позвонить, Moveне зная и не заботясь о том, что это за животное.

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

Другие формы полиморфизма : есть другой способ достижения полиморфизма, такой как интерфейсы, которые обеспечивают только полиморфизм, но не повторное использование кода (иногда код совсем другой, например, Moveдля Snake будет совсем не так, как Moveдля Dog, в этом случае Интерфейс был бы лучшим полиморфным выбором в этом случае.

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

Davy8
источник
17

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

Кроме того, полиморфизм имеет дело с вызовом метода, тогда как наследование также описывает элементы данных и т. Д.

Крис Томпсон
источник
12

В Java эти два тесно связаны. Это связано с тем, что в Java используется метод вызова метода, который называется «динамическая диспетчеризация». Если бы у меня был

public class A {
  public void draw() { ... }
  public void spin() { ... }
}

public class B extends A {
  public void draw() { ... }
  public void bad() { ... }
}

...

A testObject = new B();

testObject.draw(); // calls B's draw, polymorphic
testObject.spin(); // calls A's spin, inherited by B
testObject.bad(); // compiler error, you are manipulating this as an A

Затем мы видим, что B наследуется spinот A. Однако, когда мы пытаемся манипулировать объектом, как если бы это был тип A, мы все равно получаем поведение B для draw. drawПоведение является полиморфным.

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

В JavaScript каждый вызов функции отправляется динамически, и у вас слабая типизация. Это означает, что вы можете иметь кучу не связанных между собой объектов, каждый со своим draw, иметь функцию, перебирать их и вызывать функцию, и каждый будет вести себя просто отлично. Вы бы получили свой собственный полиморфный рисунок без необходимости наследования.

ccoakley
источник
12

Полиморфизм. Предположим, вы работаете в компании, которая продает ручки. Таким образом, вы создаете очень хороший класс под названием «Ручка», который обрабатывает все, что вам нужно знать о ручке. Вы пишете все виды классов для выставления счетов, доставки, создания счетов-фактур, все с использованием класса Pen. Приходит босс и говорит: «Отличная новость! Компания растет, и мы сейчас продаем книги и компакт-диски!» Не очень хорошая новость, потому что теперь вы должны изменить каждый класс, который использует Pen, чтобы также использовать Book & CD. Но что, если вы изначально создали интерфейс под названием «SellableProduct», а Pen реализовал этот интерфейс. Тогда вы могли бы написать все свои классы доставки, выставления счетов и т. Д., Чтобы использовать этот интерфейс вместо Pen. Теперь все, что вам нужно сделать, это создать новый класс Book & CompactDisc, который реализует интерфейс SellableProduct. Из-за полиморфизма все остальные классы могут продолжать работать без изменений! Есть смысл?

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

Полиморфизм возможен в классе / интерфейсе, но наследование всегда между 2 ИЛИ более классами / интерфейсами. Наследование всегда соответствует отношениям "есть-а", тогда как оно не всегда соответствует полиморфизму (который может соответствовать отношениям "есть-а" / "имеет-а").

AmitK
источник
6

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

Например

// This assignment is possible because B extends A
A a = new B();
// polymorphic call/ access
a.foo();

-> Хотя статический / декларационный тип a равен A, фактический динамический тип / тип времени выполнения равен B, и поэтому a.foo () будет выполнять foo, как определено в B, а не в A.

красновато-коричневый
источник
3

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

Лаз
источник
3

Наследование - это концепция, связанная с повторным использованием кода. Например, если у меня есть родительский класс say, Animalи он содержит определенные атрибуты и методы (для этого примера say makeNoise()и sleep()), и я создаю два дочерних класса с именем Dogand Cat. Так как собаки и кошки идут спать в той же манере (я предполагаю) нет необходимости добавлять больше функциональных возможностей к sleep()методу в Dogи Catподклассы , предоставляемые родительского класса Animal. Тем не менее, Dogлает и Catмяукает так, хотяAnimalу класса может быть метод создания шума, собака и кошка издают разные шумы относительно друг друга и других животных. Таким образом, существует необходимость переопределить это поведение для их конкретных типов. Таким образом, определение полиморфизма. Надеюсь это поможет.

avenger12
источник
3

Документация Oracle процитировала разницу точно.

наследование: класс наследует поля и методы от всех своих суперклассов, прямых или косвенных. Подкласс может переопределять методы, которые он наследует, или он может скрывать поля или методы, которые он наследует . (Обратите внимание, что скрытие полей - это вообще плохая практика программирования.)

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

полиморфизм не применим для полей.

Связанный пост:

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

Равиндра Бабу
источник
1

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

Например, пример полиморфизма Java:

введите описание изображения здесь

Наследование позволяет производным классам совместно использовать интерфейсы и код своих базовых классов. Это происходит во время компиляции .

Например, все классы в платформе Java являются потомками объекта (изображение любезно предоставлено Oracle):

введите описание изображения здесь

Чтобы узнать больше о наследовании Java и Java полиморфизм

Джонни
источник
0

Наследование - это когда класс A наследует все нестатические защищенные / публичные методы / поля от всех своих родителей до Object.

Космин Космин
источник
0

Если вы используете JAVA, это так просто:

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

Поправьте меня если я ошибаюсь.

Оливер Диксон
источник
0

Основное назначение полиморфизма : создание ссылочной переменной для суперкласса и удержание объекта подкласса => объект может выполнять несколько действий .

В наследство , подкласс наследует свойства суперкласса .

сатья
источник
0

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

Алиреза Рахмани Халили
источник
0

В Inheritance реализация определяется в суперклассе, поэтому поведение наследуется.

class Animal
{
  double location;
  void move(double newLocation)
  {
    location = newLocation;
  }
}

class Dog extends Animal;

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

interface Animal
{
  void move(double newLocation);
}

class Dog implements Animal
{
  double location;
  void move(double newLocation)
  {
    location = newLocation;
  }
}
mherzl
источник
0

Полиморфизм достигается путем наследования в Java.

├── Animal
└── (instances)
    ├── Cat
    ├── Hamster
    ├── Lion
    └── Moose

├── interface-for-diet
   ├── Carnivore
   └── Herbivore
├── interface-for-habitat
   ├── Pet
   └── Wild

public class Animal {
    void breath() {
    };
}

public interface Carnivore {
    void loveMeat();
}

public interface Herbivore {
    void loveGreens();
}

public interface Pet {
    void liveInside();
}

public interface Wild {
    void liveOutside();
}

public class Hamster extends Animal implements Herbivore, Pet {

    @Override
    public void liveInside() {
        System.out.println("I live in a cage and my neighbor is a Gerbil");
    }

    @Override
    public void loveGreens() {
        System.out.println("I eat Carrots, Grapes, Tomatoes, and More");
    }
}

public class Cat extends Animal implements Carnivore, Pet {
    @Override
    public void liveInside() {
        System.out.println("I live in a cage and my neighbr is a Gerbil");
    }

    @Override
    public void loveMeat() {
        System.out.println("I eat Tuna, Chicken, and More");
    }
}

public class Moose extends Animal implements Herbivore, Wild {

    @Override
    public void liveOutside() {
        System.out.println("I live in the forest");
    }

    @Override
    public void loveGreens() {
        System.out.println("I eat grass");
    }
}

public class Lion extends Animal implements Carnivore, Wild {

    @Override
    public void liveOutside() {
        System.out.println("I live in the forest");
    }

    @Override
    public void loveMeat() {
        System.out.println("I eat Moose");
    }
}

Hamsterкласс наследует структуру из Animal, Herbivoreи Petпроявлять полиморфный бихевиоризм из домашнего животного.

Catкласс наследует структуру из Animal, Carnivoreа Petтакже проявлять полиморфный бихевиоризм из домашнего животного.

nabster
источник