История вопроса:
Полиморфизм — один из ключевых принципов объектно-ориентированного программирования (ООП), который поддерживается в Java с момента её создания. Он позволяет объекту вести себя по-разному в зависимости от своего фактического типа во время выполнения программы, даже если используется ссылка базового типа.
Проблема:
Без полиморфизма код становится негибким, часто появляются избыточные конструкции вида switch-case или if-else для работы с объектами разных типов. Это усложняет поддержку и расширение кода. Полиморфизм решает проблему необходимости писать повторяющийся код для разных типов.
Решение:
Полиморфизм в Java реализован через наследование и интерфейсы. Он позволяет:
Пример кода:
class Animal { void speak() { System.out.println("Animal speaks"); } } class Dog extends Animal { @Override void speak() { System.out.println("Dog barks"); } } class Cat extends Animal { @Override void speak() { System.out.println("Cat meows"); } } public class PolyDemo { public static void main(String[] args) { Animal a1 = new Dog(); Animal a2 = new Cat(); a1.speak(); // Dog barks a2.speak(); // Cat meows } }
Ключевые особенности:
Чем отличается перегрузка (overloading) от переопределения (overriding) методов в полиморфизме?
Перегрузка — определение нескольких методов с одинаковым именем, но разной сигнатурой в одном классе. Переопределение — определение метода в подклассе с той же сигнатурой, что и в родительском классе.
class Example { void foo(int x) {} void foo(String y) {} // это перегрузка } class Base { void foo() {} } class Child extends Base { @Override void foo() {} // это переопределение }
Может ли быть полиморфизм без наследования?
В классическом понимании в Java — нет: полиморфизм требует наличия иерархии наследования или реализуемого интерфейса.
Можно ли вызывать методы подкласса из ссылки на родительский класс?
Можно вызывать только методы, определённые в родительском классе или переопределённые в подклассе. Методы, которые есть только в подклассе, вызваны быть не могут без приведения типа.
Animal a = new Dog(); a.speak(); // можно // a.fetch(); // ошибка компиляции, даже если Dog имеет метод fetch()
В проекте реализованы классы Dog, Cat, Cow, но используемый код работал напрямую с типами, вызывая методы через явные приведения и instanceof:
Плюсы:
Минусы:
Наследование Animal с виртуальным speak(). Всё взаимодействие через базовый тип Animal.
Плюсы:
Минусы: