Dziedziczenie - podstawy

Dziedziczenie to podstawowy mechanizm programowania obiektowego. Dzięki niemu możemy utworzyć spójną i łatwą do zrozumienia hierarchię klas, a to uczyni nasz kod bardziej przejrzystym i bardziej podatnym na późniejsze modyfikacje. Dziedziczenie jak sama nazwa wskazuje powoduje przekazanie pewnych cech innym klasom. Najprościej wyobrazić to sobie jako model rodziny. Dziadkowie to klasa bazowa, rodzice dziedziczą pewne cechy po dziadkach takie jak kolor oczu, wygląd - u nas byłyby to pola i metody. Dzieci z kolei mogą dziedziczyć od rodziców podobne cechy. Klasy potomne w Javie oprócz przejmowania pewnych cech mogą je także rozszerzyć i dlatego warto ich używać. Zaoszczędzi to nam pisania wielu identycznych linii kodu.

W języku Java w przeciwieństwie do innych nie występuje dziedziczenie wielokrotne. To znaczy, że klasa potomna może rozszerzać tylko jedną klasę bazową. Projektanci Javy uznali, że mechanizm taki jest prostszy i nie wprowadza niepotrzebnego chaosu.

Aby rozszerzyć jakąś klasę należy użyć słowa kluczowego extends w nagłówku klasy:

public class Szef extends Pracownik {
...
}

Łatwo sobie to wyobrazić. Szef jest także pracownikiem, więc po co tworzyć oddzielną klasę zawierającą te same wartości jedynie rozszerzone na przykład o premie, skoro można użyć dziedziczenia.

Stwórzmy więc klasę Pracownik, Szef, a także klasę Firma, w której sprawdzimy ich działanie.

class Pracownik {
    String imie;
    String nazwisko;
    int wyplata;

    public Pracownik() {
        imie = "";
        nazwisko = "";
        wyplata = 0;
    }

    public Pracownik(String i, String n, int w) {
        imie = i;
        nazwisko = n;
        wyplata = w;
    }
}

Kurs Java

Klasa Pracownik posiada 3 pola określające imię i nazwisko pracownika, a także jego wypłatę. Do tworzenia obiektów dostępne są dwa konstruktory, jeden bezparametrowy, a drugi ustawiający odpowiednie pola obiektu.

class Szef extends Pracownik {
    int premia;
}

Klasa Szef rozszerza klasę Pracownik o dodatkowe pole premia. W życiu codziennym w prawdzie zwykły pracownik też może ją otrzymać, ale załóżmy, że nie. Oczywiście obiekty typu Szef będą przechowywały także podstawowe odziedziczone dane, czyli imię, nazwisko i wypłatę. Zobaczmy więc jak to działa:

public class Firma {

    public static void main(String args[]) {
        Pracownik prac = new Pracownik("Wlodek", "Zięba", 3000);
        System.out.println("Imię: " + prac.imie);
        System.out.println("Nazwisko: " + prac.nazwisko);
        System.out.println("Wypłata: " + prac.wyplata + "\n");

        //najpierw stwórzmy obiekt klasy Szef korzystając z domyślnego konstruktora
        Szef szef = new Szef();

        //zobaczmy jak wyglądają odpowiednie pola
        System.out.println("Imię: " + szef.imie);
        System.out.println("Nazwisko: " + szef.nazwisko);
        System.out.println("Wypłata: " + szef.wyplata);
        System.out.println("Premia: " + szef.premia + "\n");

        //teraz ustawiamy dane szefa
        szef.imie = "Tadeusz";
        szef.nazwisko = "Kowalski";
        szef.wyplata = 10000;
        szef.premia = 2000;
        System.out.println("Imię: " + szef.imie);
        System.out.println("Nazwisko: " + szef.nazwisko);
        System.out.println("Wypłata: " + szef.wyplata);
        System.out.println("Premia: " + szef.premia);
    }
}

Na początku tworzymy zwykły obiekt klasy Pracownik przy pomocy konstruktora przyjmującego trzy argumenty i wyświetlamy odpowiednie pola.

Później utworzyliśmy obiekt klasy Szef przy pomocy domyślnego konstruktora i wyświetlamy "puste" wartości. Następnie do pól obiektu przypisujemy własne wartości i ponownie wyświetlamy

Jak widać klasa szef dzięki dziedziczeniu także posiada pola imie, nazwisko oraz wyplata, a dodatkowo przechowuje wartość premii, do której zwykły pracownik nie ma dostępu.

Dyskusja i komentarze

Masz pytania do tego wpisu? Może chcesz się podzielić spostrzeżeniami? Zapraszamy dyskusji na naszej grupie na Facebooku.

Poniżej znajdziesz archiwalne wpisy z czasów, gdy strona była jeszcze hobbystycznym blogiem.

Jarek

//najpierw stwórzmy domyślny obiekt klasy Szef korzystając z domyślnego konstruktora //odziedziconego z klasy Pracownik Szef szef = new Szef(); Dzień dobry. W powyższym fragmencie brakuje (chyba?) //korzystając .... Pozdrawiam, świetny kurs

Jarek

Sorry nie zauważyłem, że jest to w jednej linii. Jest OK

Carlito

A dlaczego tylko Szef ma premie : ) Na codzien programuje w c#, od paru dni ucze sie java i bardzo wiele c# zapozycza od javy. Ciekawy kurs, daje dobry obraz sytuacji. pozdrawiam

grzes

jestem przy poliformizmie i nie dajesz zadan zadnych ani nic :P

Deli

trochę inwencji twórczej :) ja jednym programem potrafię 3 i więcej lekcji ogarnąć :) programista musi miec wyobraźnie :)

kamil

skoro deklarujemy public Pracownik(){ imie = ""; nazwisko = ""; wyplata = 0; to dlaczego w szefie nie deklarujemy premii, a i tak przy pierwszym wyswietleniu jest 0 to dzieje sie automatycznie a jesli nie to dlaczego nie wyswietla tam bledu

Andrzej

Bo zadeklarowana zmienna int premia przyjmuje wartość domyślną czyli 0. Jakbyś nie zadeklarował wypłaty w konstruktorze także by się nic nie stało. Niestety ze zmiennymi (które nie są typu prostego) np. String nie można już tego zrobić, bo program się wysypie.

Mateusz Nyk

Zaczynałem programowanie w Javie od twojej strony później zacząłem czytać książkę Java Podstawy wydanie VIII ten rozdział jest bardzo podobny do opisanego w ww. książce radził bym napisać na stronach Literaturę (jak w pracy inżynierskiej, magisterskiej) żebyś nie miał w przyszłości problemów. Pozdrawiam

Slawek

Przy tworzeniu kursu przeglądam jedynie SCJP Study Guide, na stronie nie ma ani jednego zdania przepisanego z innych książek. Nie wiem co jest podobnego, ale jeśli przykład to widocznie jest najbardziej oczywistym jaki przychodzi na myśl. Książkę opisałem na stronie, jak najbardziej ją polecam, nie jest ona dla mnie jednak inspiracją, więc nie mogę jej podać jako źródła czegokolwiek na tej stronie :)

KUX

Witam, czy nie lepiej w przykladzie zamiast: public Pracownik(){ imie = ""; nazwisko = ""; wyplata = 0; } Dac: public Pracownik(){ this("", "", 0) } ??

Maciek

"//teraz ustawiamy dane szefa szef.imie = "Tadeusz"; szef.nazwisko = "Kowalski"; szef.wyplata = 10000; szef.premia = 2000; " Jesli chodzi o ten fragment, to chciałbym spytać czy podawanie wartości pola jakiejś klasy w ten sposób jest poprawne? Nie powinniśmy stworzyć metody mutatora i wtedy nadać polom wartość, a w mainie stworzyć obiekt i wywołać tą metode? byłoby to zgodne z zasadą hermetyzacji prosze o odpowiedz i pozdrawiam! :)

Sławek Ludwiczak

w ogólności powinniśmy starać się budować obiekty przetrzymujące dane w sposób o jakim piszesz, dla uproszczenia tutaj sobie to podarowałem. Gdybym pisał tę lekcję od nowa pewnie bym zrobił to tak jak napisałeś :)

Maciek

Miło usłyszeć taką odpowiedź, szczególnie, że javy ucze sie od niedawna, a udało mi sie znaleźć taki szczegół to znaczy ze coraz lepiej hehe :D

Wojciech

//Klasa Szef rozszerza klasę Pracownik nie powinno być odwrotnie? : Klasa Pracownik rozszerza klasę Szef

Damian

Nie, bo Szef posiada te 'obowiązki/przywileje' (obiekty) co pracownik + coś od siebie. Dziedziczenie ma nieco inne znaczenie, niż podpowiada intuicja ;).

Daniel

Mam problem dotyczący zainicjowania Obiektu Szef konstruktorem z parametrami: public class Pracownik{ private String Imie, Nazwisko; private int wyplata; // domyślny konstruktor Pracownik() { this.Imie = ""; this.Nazwisko = ""; this.wyplata = 2400; } // konstruktor z parametrami Pracownik(String Imie, String Nazwisko, int wyplata){ this.Imie = Imie; this.Nazwisko = Nazwisko; this.wyplata = wyplata; } // metoda wypisująca pola na ekran void PokazPracownika() { System.out.println("Imię: "+this.Imie); System.out.println("Nazwisko: "+this.Nazwisko); System.out.println("Wynagordzenie: "+this.wyplata); } } // Klasa Szef public class Szef extends Pracownik { int premia; } // Klasa glowna - firma public class Firma { public static void main(String[] args){ Szef Rejus = new Szef("Daniel","Danielowski",5000); Rejus.premia = 1000; Rejus.PokazPracownika(); System.out.println("Premia: "+Rejus.premia); } } Wyrzuca: Firma.java:7: error: constructor Szef in class Szef cannot be applied to given types; Szef Rejus = new Szef("Daniel","Danielowski",5000); ^ required: no arguments found: String,String,int reason: actual and formal argument lists differ in length 1 error To znaczy, że klasa Szef dziedziczy po klasie Pracownik tylko domyślny konstruktor? Pozdrawiam :)

Colorgreen

Witam. Mam problem z konstruktorem. public class Punkt2d{ int x; int y; public Kon1(){ int x = 0; int y = 0; } public Kon2(int a,int b){ int x = a; int y = b; } } W konsoli pisze mi error: invalid method declaration; return type required public Kon1(){ ^ Nie wiem czemu ale uznaje mi konstruktor za metode. Prosze o pomoc

Maciej

Kompilator bardzo słusznie uznał Kon1() i Kon2() za metody, bowiem kontruktor(y) zawsze ma(ją) identyczną nazwę jak klasa - w Twoim przypadku Punkt2d().

Dawid

Mam dziwny wynik. Piszę w ECLIPSE. Wynik(dlaczego jest "0") LeszekMazowiecki2000 MiroslawKrolewicz3000,0 public class Firma { public static void main(String[] args) { Pracownik worker = new Pracownik("Leszek", "Mazowiecki", 2000); System.out.println(worker.imie +worker.nazwisko +worker.wyplata); Szef szefu = new Szef("Miroslaw", "Krolewicz", 3000, 500); //test dziedziczenia System.out.println(szefu.imie +szefu.nazwisko +szefu.wyplata+ "," +szefu.premia); } } --------------- public class Pracownik { String imie; String nazwisko; int wyplata; public Pracownik(String i, String n, int w){ imie = i; nazwisko = n; wyplata = w; } } --------------- class Szef extends Pracownik { int premia; public Szef(String i, String n, int w, int premia){ super(i, n, w); } }

Dawid

Odpowiadam sam sobie :) brakowało this. class Szef extends Pracownik { int premia; public Szef(String i, String n, int w, int premia){ super(i, n, w); this.premia = premia; } }