Menu

Interfejsy w Javie: definiowanie kontraktów i implements

Czym jest interfejs w Javie, jak go zdefiniować i zaimplementować, metody default i static oraz czym interfejsy różnią się od klas abstrakcyjnych.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Interfejs to kontrakt

Interfejs deklaruje, co klasa potrafi, nie mówiąc, jak. To lista sygnatur metod, które każda implementująca go klasa obiecuje spełnić. Chodzi o rozdzielenie zależności: kod może pracować z typem interfejsu i nie przejmować się tym, jaka konkretna klasa stoi za nim.

Circle implements Shape oznacza, że Circle musi zdefiniować area i perimeter. Gdy to zrobi, Circle jest Shape i można go przechowywać w zmiennej typu Shape.

Wiele klas, jeden typ

Siła interfejsów widać wtedy, gdy kilka niepowiązanych klas implementuje ten sam interfejs. Kod napisany pod Shape obsługuje je wszystkie:

Pętla nigdy nie pyta „czy to Circle, czy Rectangle?”. Po prostu wywołuje area() i ufa kontraktowi. Dodanie później klasy Triangle nie wymaga tu żadnej zmiany.

Implementowanie wielu interfejsów

Klasa rozszerza tylko jedną klasę, ale może implementować dowolną liczbę interfejsów. Tak Java bezpiecznie realizuje „wielokrotne dziedziczenie” zachowania:

Wypisz interfejsy po przecinku po implements. Klasa musi spełnić je wszystkie.

Metody default i static

Od Javy 8 interfejs może zawierać ciała metod. Metoda default daje klasom implementującym gotową implementację, którą dziedziczą za darmo (i mogą nadpisać):

Metody default pozwalają interfejsowi ewoluować: można dodać metodę, nie psując żadnej istniejącej implementacji. Metoda static interfejsu działa natomiast jak inne składowe statyczne: to funkcja pomocnicza wywoływana na samym interfejsie, na przykład Comparator.naturalOrder().

Stałe

Pola w interfejsie są niejawnie public static final: to stałe, a nie stan instancji:

interface Physics {
    double GRAVITY = 9.81;   // automatically public static final
}

Interfejsy tradycyjnie nie przechowują stanu poszczególnych obiektów. Brak pól instancji to część tego, co odróżnia je od klas.

Interfejsy funkcyjne

Interfejs z dokładnie jedną metodą abstrakcyjną to interfejs funkcyjny i możesz go zaimplementować wyrażeniem lambda zamiast całej klasy:

To podstawa lambd w Javie i typów z java.util.function (Function, Predicate, Supplier i pokrewnych). Adnotacja @FunctionalInterface jawnie pokazuje intencję i pozwala kompilatorowi pilnować zasady jednej metody.

Interfejs a klasa abstrakcyjna

Oba pozwalają programować pod abstrakcję, więc kiedy wybrać które?

  • Interfejs: zdolność, którą mogą współdzielić niepowiązane klasy. Bird i Airplane mogą być jednocześnie Flyable. Klasa może implementować wiele interfejsów. Brak stanu instancji.
  • Klasa abstrakcyjna: wspólny stan i kod blisko spokrewnionych klas. Cat i Dog rozszerzają Animal, dziedzicząc wspólne pola i częściowo zaimplementowane metody. Klasa rozszerza tylko jedną.

Popularny wzorzec łączy oba podejścia: interfejs definiuje kontrakt, a klasa abstrakcyjna implementuje powtarzalne części, więc konkretne podklasy uzupełniają tylko szczegóły.

Dalej: klasy abstrakcyjne

Interfejsy definiują zachowanie bez stanu. Klasy abstrakcyjne leżą pomiędzy interfejsami a pełnymi klasami: mogą deklarować niezaimplementowane metody i mieć pola oraz konstruktory. O tym jest następna strona.

Najczęściej zadawane pytania

Czym jest interfejs w Javie?

Interfejs to kontrakt: zestaw sygnatur metod (i stałych), które klasa obiecuje dostarczyć. Mówi, co klasa potrafi, a nie jak to robi. Klasa przyjmuje interfejs słowem kluczowym implements i musi dostarczyć ciało każdej metody abstrakcyjnej, którą interfejs deklaruje. Dzięki interfejsom niepowiązane ze sobą klasy można stosować zamiennie przez wspólny typ.

Czym różni się interfejs od klasy abstrakcyjnej w Javie?

Klasa może implementować wiele interfejsów, ale rozszerzać tylko jedną klasę (abstrakcyjną). Interfejsy tradycyjnie nie przechowują stanu instancji i tylko deklarują zachowanie, a klasa abstrakcyjna może mieć pola, konstruktory i częściowo zaimplementowaną logikę. Użyj interfejsu, by zdefiniować zdolność, którą może współdzielić kilka niepowiązanych klas. Użyj klasy abstrakcyjnej, by współdzielić stan i kod między blisko spokrewnionymi podklasami.

Czy interfejs w Javie może mieć ciała metod?

Tak, od Javy 8. Metody interfejsu oznaczone jako default mają ciało, które klasy implementujące dziedziczą (i mogą nadpisać), a metody static interfejsu dostarczają funkcje pomocnicze wywoływane na samym interfejsie. Zwykłe metody interfejsu nadal są abstrakcyjne, czyli to sama sygnatura, i klasy implementujące muszą je zdefiniować.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ