środa, października 13, 2010

Konstruktory

[Tu uwaga, już to raz dziś pisałem, ale wysiadła mi bateria w G1 i muszę pisać od nowa, co oznacza też, że do Bloggeroida dodam nagrywanie co jakiś czas edytowanego posta do Bloggera albo na SD w ramach autosave :-), nowa bateria już zamówiona na Amazon.co.uk :-)]

Dziś trafił do mnie ktoś szukający czegoś o dziedziczeniu konstruktorów.
Konstruktorów się nie dziedziczy! Koniec i kropka!
Odpowiedź na pytanie o dziedziczenie konstruktorów brzmi - NIE!

Dlaczego?

To proste, nie dziedziczmy konstruktorów bo to bez sensu ;-)

Po pierwsze. Co miałby zrobić taki "zadziedziczony" konstruktor z polami nowego obiektu? Oczywiście może jest zostawić tak jak są, ale to znaczy, że obiekt będzie potencjalnie nie w pełni zainicjowany.
Oczywiście jako programista można uznać, że to jest OK, ale w takim przypadku wystarczy dodać własny konstruktor, który wywoła po prostu odpowiedni konstruktor z nadklasy.
Po drugie. Dziedziczenie konstruktorów ograniczałoby możliwość tworzenia nowych klas potomnych. Trzeba by było nieść ze sobą cały bagaż wcześniejszych konstruktorów. Robi się tak w przypadku metod. Z tym, że metody używając polimorfizmu operują na pewnym fragmencie obiektu wypełniając kontrakt interfejsu. Jeśli przez jakieś pokrzywione ścieżki rozumowania dotrzemy do etapu, że klasa Kwadrat będzie rozszerzać Prostokąt to metoda liczObwód ma sens w obu przypadkach, ale z konstruktorami tak łatwo nie jest, jeśli mieliśmy Prostokąt(float, float) to teraz mielibyśmy też Kwadrat(float, float), czyli potencjalnie moglibyśmy mieć kwadrat o różnych bokach ;-)
Po trzecie. Nie dałoby się np. zrobić singletona, bo do tego trzeba schować wszystkie konstruktory, a gdyby były dziedziczone to by się tego nie dało zrobić, gdyż z dziedziczeniem dopuszczalne jest tylko zwiększanie widoczności, nie zmniejszanie widoczności.
Inna sprawa, że konstruktorowi trudno byłoby być polimorficznym, jakby to miało działać? Jak miałoby wyglądać wywołanie?

Teraz jeszcze o zamęcie w Java'ie, który może powodować, że wydaje się, że konstruktory są dziedziczone.
Po pierwsze, gdy Twoja klasa nie ma jawnie zadeklarowanego konstruktora to kompilator Java'y doda jej bezparametrowy konstruktor domyślny, który będzie składał się z 1 linii, w której będzie wołany konstruktor bezparametrowy z nadklasy (przez super()). Dlatego jeśli nadklasa nie ma konstruktora bezparametrowego to sorry Winetou, dostaniesz błąd czasu kompilacji.
Po drugie, konstruktor klasy potomnej musi wołać konstruktor nadklasy. Może to robić jawnie przez wołanie super z odpowiednimi parametrami, albo jeśli to się nie dzieje to Java doda sama wołanie super() do konstruktora. Co znów nie zadziała jeśli Twoja nadklasa nie ma konstruktora domyślnego, wtedy trzeba będzie jawnie zawołać super z odpowiednimi parametrami.

Na koniec jeszcze raz to napiszę bo to ważne, a wiele osób o tym nie pamięta - KONSTRUKTORÓW SIĘ NIE DZIEDZICZY!


Podobne postybeta
Refleksje i serializacja w Java'ie - podstawy i obalanie mitów ;-)
Drugi klasyfikator jako "sanity check"
Giń konstruktorze! Giń! ;-)
Go dla Java'owca ;-) odcinek 1 "klasy"
Android nie taki zły ;-)