Java - dziedziczenie

29 maja 2026 13:29

Dziedziczenie w Javie – Budowanie Hierarchii Klas

Po lekturze tego rozdziału dowiesz się:

Czym jest dziedziczenie?

Wyobraź sobie, że piszesz program do zarządzania wypożyczalnią pojazdów. Masz w nim samochody, motocykle i ciężarówki. Każdy z tych pojazdów ma markę, model, rok produkcji i metodę uruchomSilnik(). Zamiast pisać ten sam kod trzy razy dla każdej z klas, możesz stworzyć jedną, ogólną klasę Pojazd, a następnie nakazać klasom Samochod, Motocykl i Ciezarowka przejęcie (odziedziczenie) jej właściwości.

Dziedziczenie to mechanizm pozwalający jednej klasie (klasie pochodnej) na uzyskanie dostępu do pól i metod innej klasy (klasy bazowej). Służy ono przede wszystkim do ponownego wykorzystania kodu (zasada DRY – Don't Repeat Yourself) oraz tworzenia logicznych, hierarchicznych relacji typu "IS-A" (jest czymś).

Przykład: Samochód jest pojazdem (Samochod IS-A Pojazd). Pies jest zwierzęciem (Pies IS-A Zwierze).

Słowo kluczowe extends

Aby wskazać, że jedna klasa dziedziczy po innej, w Javie używamy słowa kluczowego extends (rozszerza).

Przykład w kodzie:

// 1. Superklasa (Klasa bazowa)
public class Pojazd {
    protected String marka;
    
    public void trab() {
        System.out.println("Beep! Beep!");
    }
}

// 2. Podklasa (Klasa pochodna)
public class Samochod extends Pojazd {
    private String model;
    
    public Samochod(String marka, String model) {
        this.marka = marka; // Dostęp do pola z klasy Pojazd
        this.model = model;
    }
    
    public void wyswietlInfo() {
        System.out.println("To jest " + marka + " " + model);
    }
}

W powyższym przykładzie klasa Samochod ma dostęp do metody trab() oraz pola marka, mimo że nie zostały one w niej bezpośrednio zadeklarowane.

Co jest dziedziczone, a co nie?

Podklasa dziedziczy po superklasie wszystko z wyjątkiem pewnych ściśle określonych elementów. Reguły dostępu dyktują modyfikatory dostępu:

Modyfikator Czy dziedziczone do podklasy w tym samym pakiecie? Czy dziedziczone do podklasy w innym pakiecie?
public Tak Tak
protected Tak Tak
default (brak) Tak Nie
private Nie Nie

Ważna uwaga: Konstruktory nigdy nie są dziedziczone! Podklasa musi zdefiniować własne konstruktory, ale może (i często musi) wywołać w nich konstruktor superklasy.

Słowo kluczowe super

Słowo kluczowe super działa podobnie do this, ale zamiast wskazywać na obecny obiekt, wskazuje na bezpośrednią klasę nadrzędną (rodzica). Używamy go w dwóch głównych przypadkach:

  1. Wywołanie konstruktora rodzica: super()
  2. Dostęp do przesłoniętych metod lub ukrytych pól rodzica: super.nazwaMetody()

Każdy konstruktor podklasy domyślnie wywołuje bezparametrowy konstruktor rodzica (super()) jako swoją pierwszą instrukcję, nawet jeśli tego nie napiszesz. Jeśli rodzic ma tylko konstruktory z parametrami, musisz wywołać super(...) jawnie.

public class Pracownik {
    String imie;
    
    public Pracownik(String imie) {
        this.imie = imie;
    }
}

public class Programista extends Pracownik {
    String jezykProgramowania;
    
    public Programista(String imie, String jezykProgramowania) {
        super(imie); // MUSI być pierwszą instrukcją! Wywołuje konstruktor klasy Pracownik
        this.jezykProgramowania = jezykProgramowania;
    }
}

Przesłanianie metod (Method Overriding)

Często zdarza się, że podklasa dziedziczy metodę od rodzica, ale potrzebuje, aby ta metoda działała inaczej. Proces definiowania na nowo odziedziczonej metody nazywamy przesłanianiem (overriding).

Aby prawidłowo przesłonić metodę, należy użyć adnotacji @Override. Nie jest ona obowiązkowa dla kompilatora, ale chroni przed literówkami (np. napisaniem Trab() zamiast trab()) i jasno komunikuje intencje programisty.

public class Zwierze {
    public void dajGlos() {
        System.out.println("Zwierzę wydaje dźwięk");
    }
}

public class Kot extends Zwierze {
    @Override
    public void dajGlos() {
        System.out.println("Miau!"); // Zmiana zachowania metody rodzica
    }
}

Kosmiczny rodzic: Klasa Object

W Javie panuje zasada absolutnej hierarchii. Każda klasa, którą stworzysz, domyślnie dziedziczy po wbudowanej klasie java.lang.Object. Nawet jeśli nie napiszesz extends Object, kompilator zrobi to za Ciebie.

Dzięki temu każdy obiekt w Javie posiada standardowy zestaw metod, takich jak:

Często będziesz przesłaniać te metody we własnych klasach, aby dostosować je do własnych potrzeb.

Ograniczenia dziedziczenia

Java wprowadza pewne restrykcje, o których musisz pamiętać projektując strukturę aplikacji:

  1. Brak wielokrotnego dziedziczenia klas: W Javie klasa może dziedziczyć tylko po jednej innej klasie (np. class A extends B, C wygeneruje błąd kompilacji). Zabezpiecza to przed problemem "Diamentowego Dziedziczenia" (Diamond Problem). Aby obejść to ograniczenie, Java używa interfejsów (omówionych w kolejnym wpisie).
  2. Klasy ostateczne (final): Jeśli nie chcesz, aby jakakolwiek klasa mogła dziedziczyć po Twojej klasie, możesz użyć słowa kluczowego final. (np. public final class String - nie możesz stworzyć własnej podklasy klasy String).

Podsumowanie