Strona główna > Kursy > Java dla testerów > Java dla Testerów 23. Klasy abstrakcyjne i interfejsy

Java dla Testerów 23. Klasy abstrakcyjne i interfejsy

Jednym z klasycznych wręcz pytań na rozmowach rekrutacyjnych, w których sprawdzana jest znajomość programowania obiektowego w Javie, jest pytanie o klasy abstrakcyjne i interfejsy. Czym się charakteryzują, jakie są między nimi różnice, a jakie są podobieństwa? Wszystkiego się dowiesz z poniższego nagrania spotkania LIVE.

Klasy abstrakcyjne

Klasy abstrakcyjne w odróżnieniu od zwykłych klas, nie mogą mieć swoich obiektów, tj. nie mozemy stworzyć obiektu takiej klasy za pomocą konstruktora. Klasy abstrakcyjne służą raczej jako baza dla innych klas. Nie można utworzyć obiektu klasy abstrakcyjnej, ale można dziedziczyć po niej i rozszerzać ją w innych klasach.

Klasy abstrakcyjne są bardzo przydatne, gdy mamy do czynienia z grupą obiektów, które mają wiele wspólnych cech. Abstrakcyjna klasa bazowa ma jedynie umożliwiać zdefiniowanie zachowań i cech wspólnych. Na przykład, mamy klasę abstrakcyjną User, która reprezentuje ogólnego użytkownika systemu do logowania na uczelni. Klasy Student i Professor dziedziczą po User i rozszerzają go o dodatkowe funkcjonalności, odpowiednie dla studenta i profesora. Dzięki temu możemy wyodrębnić wspólne cechy użytkowników systemu i jednocześnie zapewnić unikalne funkcjonalności dla studentów i profesorów. User w takim przypadku jest tylko bazową klasą pomocniczą i nigdy nie będziemy chcieli tworzyć obiektów tej klasy bezpośrednio. Dlatego możemy z niej zrobić klasę abstrakcyjną i tym samym „zablokować” możliwość tworzenia obiektów tej klasy.

Aby utworzyć klasę abstrakcyjną w Javie, należy użyć słowa kluczowego abstract, np. abstract class User. W klasie abstrakcyjnej możemy zdefiniować zmienne i metody, tak jak w zwykłej klasie. Jednak w przeciwieństwie do zwykłej klasy, w klasie abstrakcyjnej możemy również zdefiniować metody abstrakcyjne.

Metody abstrakcyjne są to metody, które nie posiadają implementacji w klasie abstrakcyjnej, ale muszą być zaimplementowane w klasach potomnych. Oznaczamy je za pomocą słowa kluczowego abstract, np. abstract void login(). Klasy potomne, które dziedziczą po abstrakcyjnej klasie, muszą zaimplementować wszystkie abstrakcyjne metody swojej klasy nadrzędnej. W ten sposób możemy uniknąć sytuacji, w której klasa dziedzicząca nie posiada wszystkich cech swojej klasy nadrzędnej.

W testowaniu oprogramowania klasy abstrakcyjne mogą nam się przydać na przykład w testach Selenium opartych o Page Object Model i dziedziczenie. Wtedy klasa BasePage, będąca bazą dla każdej klasy Page Object, będzie klasą abstrakcyjną.

Interfejsy

Interfejsy są podobne do klas, ale nie mogą zawierać implementacji metod, a jedynie ich sygnaturę (z pewnymi wyjątkami, o których w dalszej części tekstu). Interfejsy służą jako wzorzec do implementacji, ale nie posiadają własnej implementacji.

Interfejsy są używane w celu zapewnienia, że klasy, które implementują dany interfejs, posiadają wymagane metody i pola. Dzięki temu możemy być pewni, że klasy te będą działać w określony sposób i będą posiadać wymagane funkcjonalności. Aby stworzyć interfejs w Javie, należy użyć słowa kluczowego interface, na przykład public interface Employee.

Interfejsy mogą zawierać zarówno metody abstrakcyjne, jak i metody, które mają implementację. Metody abstrakcyjne nie posiadają implementacji (jedynie sygnaturę) i muszą być zaimplementowane przez klasy, które implementują dany interfejs. W kalsach abstrakcyjnych takie metody musiały być oznaczone słówkiem abstract, w interfejsach nie muszą.

Metody z implementacją to na przykład metody domyślne oznaczone słówkiem default. Inne metody, które mogą mieć implementację w interfejsie to metody statyczne oraz niestatyczne metody prywatne. Interfejsy nie mogą zawierać konstruktorów, niepublicznych metod abstrakcyjnych oraz pól innych niż public static final (chociaż wcale nie musimy pól oznaczać tymi słówkami, po prostu będą takie domyślnie).

Aby klasa mogła implementować dany interfejs, należy użyć słowa kluczowego implements i określić nazwę interfejsu, który ma być implementowany, na przykład public class OfficeWorker implements Employee. Każda klasa może implementować dowolną ilość interfejsów. Interfesy mogą z kolei rozszerzać dowolną ilość interfejsów. Do rozszerzania interfejsów przez inne interfejsy używamy słówka extends, np. public interface Employee extends User.

Klasy abstrakcyjne i interfejsy: różnice

  • Klasa abstrakcyjna może mieć abstrakcyjne i nieabstrakcyjne metody instancyjne, podczas gdy interfejs może mieć abstrakcyjne albo domyślne metody instancyjne.
  • Klasa abstrakcyjna może rozszerzać inną klasę abstrakcyjną lub nie abstrakcyjną, podczas gdy interfejs może rozszerzać tylko interfejsy.
  • Interfejs pozwala na wielokrotne dziedziczenie.
  • Klasa abstrakcyjna może mieć zmienne statyczne, niestatyczne, final, czy nie, a interfejs może mieć tylko public final static.
  • Klasa abstrakcyjna może implementować interfejs, ale interfejs nie może implementować klasy abstrakcyjnej.
  • Klasa abstrakcyjna może mieć konstruktor, interfejs nie.
  • W klasie abstrakcyjnej słówko abstract jest obowiązkowe jeżeli chcemy zadeklarować metodę abstrakcyjną, w interfejsie jest to opcjonalne.

Chcesz poćwiczyć Javę w zadaniach? Dołącz do 5-dniowego wyzwania!

Codziennie dostaniesz jedno zadanie do rozwiązania, a następnego dnia przykładowe rozwiązania z komentarzem.