Kurs Java

Klasy abstrakcyjne

W naszym kursie Java wielokrotnie pisaliśmy już o klasach i zawsze wskazywaliśmy na fakt, że z danej klasy można stworzyć wiele obiektów. Pytanie jednak czy zawsze i wszędzie można w Javie stworzyć obiekt na podstawie istniejącego egzemplarza klasy? Okazuje się, że jednak nie. Istnieje bowiem specjalny rodzaj klas, których ta zasada nie dotyczy. Ten specjalny rodzaj klas to klasy abstrakcyjne.

Klasa abstrakcyjna - Podstawowa definicja

Klasa abstrakcyjna jest klasą, z której nie można utworzyć instancji obiektu. Posiada ona następujące własności:
  • Oznaczamy ją modyfikatorem abstract.
  • Klasa może (ale nie musi) zawierać zarówno regularne metody Java jak i takie oznaczone modyfikatorem abstract.
  • Klasa abstrakcyjna może być rozszerzana przez inne klasy Java - zarówno zwykłe jak i abstrakcyjne.
W Javie możemy rozszerzać tylko jedną klasę na raz i tak samo jest w przypadku klas abstrakcyjnych.

Przykład klasy abstrakcyjnej

Pamiętacie nasze klasy Item oraz DocumentItem? Jeśli nie to przypominamy, że w rozdziale Klasy - Dziedziczenie (Inheritance) przedstawiliśmy dziedziczenie klasy DocumentItem z klasy Item. W jednym z pierwszych przykładów określiliśmy wtedy, że klasa Item zawiera pole name wraz z metodami dostępowymi do tego pola:
public class Item {

    String name;       
    
    public void setName(String name) {
        this.name = name;
    }    
    
    public String getName() {
        return name;
    }

} 
public class DocumentItem extends Item {


} 
Klasa Item jest zwykłą klasą Java i nie ma jak narazie nic wspólnego z omawianym przez nas tutaj tematem klas abstrakcyjnych. Nic jednak nie stoi na przeszkodzie, abyśmy przerobili tę klasę na klasę abstrakcyjną. W tym celu dopisujemy wspomniany wyżej modyfikator abstract:
public abstract class Item {

    String name;       
    
    public void setName(String name) {
        this.name = name;
    }    
    
    public String getName() {
        return name;
    }

} 
To wszystko. Tyle wystarczy, aby nasza klasa stała się klasą abstrakcyjną. Teraz w dalszym ciągu klasa DocumentItem może dziedziczyć z klasy Item. Tak samo możemy stworzyć inne klasy, na przykład MovieItem czy ProductItem i one także będą mogły dziedziczyć z naszej klasy abstrakcyjnej. Oczywiście będziemy mogli tworzyć obiekty tych klas, na przykład:
new MovieItem();
To co nie będzie możliwe, to stworzenie obiektu bezpośrednio z klasy Item:
new Item();
Taka próba zakończy się od razu błędem kompilacji.

Metoda abstrakcyjna

Dobrze, mamy zatem stworzoną naszą pierwszą klasę abstrakcyjną, ale co nam to właściwie daje?

Po pierwsze, napotykając taką klasę w kodzie od razu wiemy, że jest ona tylko i wyłącznie bazą do tworzenia innych klas. Mówimy, że jest ona pewnego rodzaju projektem, który następnie powinien zostać odpowiednio zaimplementowany w klasach podrzędnych (dziedziczących).

Do stworzenia takiego projektu wymagane jest jednak coś więcej niż tylko słowo abstract użyte przed nazwą klasy. W tym celu potrzebujemy stworzyć przynajmniej jedną metodę abstrakcyjną.

Metody abstrakcyjne w Javie charakteryzują się tym, że:
  • Oznaczamy je modyfikatorem abstract.
  • Nie posiadają swojego ciała, a jedynie deklaracje w postaci nazwy metody wraz z listą parametrów (albo bez parametrów).
I teraz możemy na przykład stworzyć wymaganie, aby każda klasa dziedzicząca z klasy Item oprócz nazwy zwracała jeszcze opis. Wprowadzamy więc do klasy Item metodę abstrakcyjną o nazwie getDescription().
public abstract class Item {

    String name;       
    
    public void setName(String name) {
        this.name = name;
    }    
    
    public String getName() {
        return name;
    }

    public abstract String getDescription();
} 
Metoda ta nie posiada ciała. Jej przeznaczeniem jest wymuszenie na każdej klasie implementującej, aby dostarczyła ciało tej metody. Inaczej mówiąc, teraz do naszej klasy DocumentItem musimy dodać metodę getDescription wraz z jej ciałem:
public class DocumentItem extends Item {

    public String getDescription() {
        return "This is description for DocumentItem";
    }
} 
W ten sposób dostarczyliśmy implementację metody abstrakcyjnej. Warto podkreślić, że w przypadku braku tej metody, klasa DocumentItem nie skompiluje się. Tak to działa w przypadku klas nieabstrakcyjnych. W przypadku gdy jedna klasa abstrakcyjna dziedziczy z drugiej klasy abstrakcyjnej, nie musimy implementować w niej metod abstrakcyjnych. Kompilacja się powiedzie.

Na koniec kilka słów o użyteczności abstrakcji. W programowaniu istnieje silna potrzeba definiowania pewnego szkieletu ogólnych zachowań bez stosowania szczegółowej implementacji. Tworząc system informatyczny nie musimy się na przykład od samego początku zastanawiać nad tym w jaki sposób będziemy odczytywać dane (czy z bazy danych, czy z pliku, czy też innej usługi). Na tym etapie interesuje nas, aby dany system w ogóle miał możliwość odczytu danych, a do tego wystarczy nam zadeklarowanie metody bez ciała. Implementacje możemy dołożyć w późniejszym czasie w postaci nieabstrakcyjnej klasy dziedziczącej.
Zdjęcie autora
Autor: Jarek Klimas
Data: 03 stycznia 2024
Labele: Backend, Podstawowy, Java
Masz pytanie dotyczące tego rozdziału? Zadaj je nam!
Masz pytanie dotyczące prezentowanego materiału?
Coś jest dla Ciebie niejasne i Twoje wątpliwości przeszkadzają Ci w pełnym zrozumieniu treści?
Napisz do nas maila, a my chętnie znajdziemy odpowiednie rozwiązanie.
Najciekawsze pytania wraz z odpowiedziami będziemy publikować pod rozdziałem.
Nie czekaj. Naucz się programować jeszcze lepiej.
kursjava@javappa.com

Stale się rozwijamy, a więc bądź na bieżąco!
Na ten adres będziemy przesyłać informacje o ważniejszych aktualizacjach, a także o nowych materiałach pojawiających się na stronie.
Polub nas na Facebooku:
Nasi partnerzy: stackshare
Javappa to również profesjonalne usługi programistyczne oparte o technologie JAVA. Jeśli chesz nawiązać z nami kontakt w celu uzyskania doradztwa bądź stworzenia aplikacji webowej powinieneś poznać nasze doświadczenia.
Kliknij O nas .


Pozycjonowanie stron: Grupa TENSE