W Javie rozwiązywanie przeciążeń (overloading) i nadpisywanie (overriding) metod odbywa się zgodnie z określonymi zasadami. Przy przeciążeniu (overloading) kompilator wybiera najbardziej odpowiednią metodę spośród wszystkich wersji na etapie kompilacji, bazując na typie argumentów w miejscu wywołania.
WaŜne punkty:
Przykład:
class Super { void print(Number n) { System.out.println("Super Number"); } } class Sub extends Super { void print(Integer i) { System.out.println("Sub Integer"); } } ... Sub s = new Sub(); s.print(5); // Sub Integer s.print(5.0); // Super Number
Tutaj print(Integer) zostanie wywołane dla argumentu typu Integer, a dla typu Double — metoda rodzicielska.
Jeśli w dziedziczeniu metoda została nadpisana (override) i przeciążona (overload), która z nich zostanie wywołana przy polimorfizmie?
Odpowiedź: Przy polimorfizmie zawsze wybierana jest wersja metody na podstawie rzeczywistego typu obiektu dla metod nadpisanych (overriding). Dla metod przeciążonych wybór odbywa się na etapie kompilacji na podstawie typu odniesienia.
class A { void test(Number n) { System.out.println("A:Number"); } } class B extends A { void test(Integer n) { System.out.println("B:Integer"); } @Override void test(Number n) { System.out.println("B:Number"); } } ... A obj = new B(); obj.test(1); // Wywoła B:Number, mimo że istnieje test(Integer)
Historia
Programista dodał przeciążoną wersję metody do podklasy, spodziewając się, że zostanie ona wywołana dla wszystkich dziedziców. W produkcji okazało się, że wywołanie przez odniesienie do klasy rodzicielskiej prowadzi do wyboru metody na podstawie typu odniesienia, a nie obiektu. W efekcie wymagana logika nie była wykonywana.
Historia
W dużym projekcie błędnie przeciążono metodę equals(Object) z sygnaturą equals(MyClass obj), myśląc, że zastąpi standardowy equals. Przy porównaniach w kolekcjach HashSet działał domyślny equals(Object), co prowadziło do braku zgodności logiki i utraty danych.
Historia
Przy dodawaniu nowej wersji metody z varargs do hierarchii klas wydawało się, że dla tablic zostanie wywołana potrzebna wersja. Jednak przy przekazywaniu tablicy jawnie, kompilator wybrał nie to przeciążenie, w rezultacie czego przetwarzanie przebiegało niepoprawnie, a błąd długo pozostawał niezauważony.