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

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

Предположим, что у меня есть два класса: Animal and Dog. Собака является подклассом Animal. Я делаю следующий код:

Animal a = new Dog();

Теперь я могу вызывать методы класса Dog через переменную.

Но мой вопрос заключается в следующем: если я могу вызвать все методы Animal через объекты Dog (наследование), чем использовать принцип полиморфизма? Я могу просто объявить:

Dog d = new Dog();

В этом объявлении можно использовать все методы Animal и Dog. Так зачем использовать полиморфизм? Большое спасибо за ваш ответ.

4b9b3361

Ответ 1

В Java понятия полиморфизма и наследования "свариваются"; в общем, это не должно быть так:

  • Полиморфизм позволяет вам вызывать методы класса, не зная точного типа класса
  • Наследование позволяет производным классам совместно использовать интерфейсы и код их базовых классов

Существуют языки, где наследование отделяется от полиморфизма:

  • В С++ вы можете наследовать класс без создания полиморфного поведения (т.е. не помечать функции в базовом классе с помощью virtual)
  • В Objective C вы можете реализовать метод для несвязанного класса и вызвать его из места, которое знает только сигнатуру метода.

Возвращаясь к Java, причина использования полиморфизма - это развязка вашего кода от деталей реализации его сторонних сторон: например, если вы можете написать метод Feed(Animal animal), который работает для всех видов животных, метод будет оставаться применимым, если вы добавите дополнительные подклассы или реализации Animal. Это контрастирует с методом Feed(Dog dog), который будет тесно связан с собаками.

Что касается

Dog d = new Dog();

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

List<Integer> numbers = new ArrayList<Integer>();

В подобных случаях вы можете заменить new ArrayList<Integer>() на new LinkedList<Integer>() и знать, что ваш код будет компилироваться. Напротив, если ваш список numbers был объявлен как ArrayList<Integer> numbers, такое переключение может быть не уверенным.

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

Ответ 2

У вас могут быть другие реализации класса Animal, например Cat. Тогда вы можете сказать

Animal a = new Dog();
Animal b = new Cat();

Вы можете вызвать методы класса Animal, не заботясь о том, какая реализация на самом деле есть, а polymorphism вызовет правильный метод. Например.

a.speak();  // "Woof"

b.speak();  // "Meow"

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

Ответ 3

Полиморфизм позволяет вам написать метод, который работает для любого Animal:

public void pet(Animal animal) {
   ...
}

Этот метод принимает Dog, Cat и т.д., включая подклассы Animal, которые еще не записаны.

Если бы метод принимал Dog, это не сработало бы для Cat и т.д.

Ответ 4

Если вы уверены, что всегда будет собакой, для этого нет причин. Вы можете использовать Dog d = new Dog(); как вы описали. Но скажем, вы использовали метод вместо конструктора. Метод вернул животное, и вы не знаете, какую реализацию животного вы получите. Вы все равно сможете использовать те же методы для животного (даже если это собака, кошка-слон и т.д.).

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

Ответ 5

Обычно заданный вами вопрос больше похож на Inheritance vs Composition:). Еще один пример "реальной жизни", почему полезно использовать полиморфизм, например, использование шаблона проектирования стратегии. У вас может быть много реализаций TaxPolicy: UsaTaxPolicy, CanadaTaxPolicy, EuTaxPolicy и т.д. Если у вас есть метод calculateFinalPrice, который также должен рассчитать налог, то вы вводите правильную реализацию, и выполняется хороший расчет, независимо от того, вы прошли через Usa, Canada или Eu.

Ответ 6

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