Historia pytania:
Polimorfizm to jedna z kluczowych zasad programowania obiektowego (OOP), która jest wspierana w Javie od samego jej powstania. Pozwala obiektowi zachowywać się różnie w zależności od swojego rzeczywistego typu w czasie wykonywania programu, nawet jeśli używana jest referencja typu bazowego.
Problem:
Bez polimorfizmu kod staje się mało elastyczny, często pojawiają się nadmiarowe konstrukcje typu switch-case lub if-else do pracy z obiektami różnych typów. Utrudnia to utrzymanie i rozwój kodu. Polimorfizm rozwiązuje problem konieczności pisania powtarzającego się kodu dla różnych typów.
Rozwiązanie:
Polimorfizm w Javie jest realizowany poprzez dziedziczenie i interfejsy. Pozwala na:
Przykład kodu:
class Animal { void speak() { System.out.println("Zwierzę mówi"); } } class Dog extends Animal { @Override void speak() { System.out.println("Pies szczeka"); } } class Cat extends Animal { @Override void speak() { System.out.println("Kot miauczy"); } } public class PolyDemo { public static void main(String[] args) { Animal a1 = new Dog(); Animal a2 = new Cat(); a1.speak(); // Pies szczeka a2.speak(); // Kot miauczy } }
Kluczowe cechy:
Czym różni się przeciążanie (overloading) od nadpisywania (overriding) metod w polimorfizmie?
Przeciążanie to definiowanie kilku metod o tej samej nazwie, ale różnej sygnaturze w jednej klasie. Nadpisywanie to definiowanie metody w podklasie o tej samej sygnaturze, co w klasie bazowej.
class Example { void foo(int x) {} void foo(String y) {} // to jest przeciążanie } class Base { void foo() {} } class Child extends Base { @Override void foo() {} // to jest nadpisywanie }
Czy polimorfizm może istnieć bez dziedziczenia?
W klasycznym rozumieniu w Javie — nie: polimorfizm wymaga istnienia hierarchii dziedziczenia lub implementowanego interfejsu.
Czy można wywoływać metody podklasy z referencji do klasy bazowej?
Można wywoływać tylko metody zdefiniowane w klasie bazowej lub nadpisane w podklasie. Metody, które występują tylko w podklasie, nie mogą być wywołane bez rzutowania typu.
Animal a = new Dog(); a.speak(); // można // a.fetch(); // błąd kompilacji, nawet jeśli Dog ma metodę fetch()
W projekcie zaimplementowane zostały klasy Dog, Cat, Cow, ale używany kod pracował bezpośrednio z typami, wywołując metody przez jawne rzutowania i instanceof:
Zalety:
Wady:
Dziedziczenie Animal z wirtualnym speak(). Cała interakcja przez typ bazowy Animal.
Zalety:
Wady: