Kurs Java

Interfejsy

W poprzednim rozdziale omawialiśmy klasy abstrakcyjne, a teraz zajmiemy się innym sposobem na zbudowanie abstrakcji w Javie. Mamy tu na myśli interfejsy, które w pewnym sensie przypominają klasy abstrakcyjne.

Z klasy abstrakcyjnej do interfejsu

Wyobraźmy sobie klasę abstrakcyjną, której wszystkie metody mają modyfikator abstract. Za przykład niech posłuży nam klasa z poprzedniego rozdziału, w której zmieniamy dodatkowo metody getName i setName, tak aby były metodami abstrakcyjnymi:
public abstract class Item {     
    
    public abstract void setName(String name);
    
    public abstract String getName();

    public abstract String getDescription();
} 
Cechą charakterystyczną tej klasy jest to, że nie dostarcza ona implementacji żadnej metody. Posiada tylko deklaracje metod. Jak wiemy implementacje metod muszą zostać dostarczone przez klasy nieabstrakcyjne, które będą rozszerzać tę klasę.

Teraz pójdziemy krok dalej w naszych modyfikacjach i zamiast słowa class wpiszemy słowo interface. Po wykonaniu zmiany otrzymamy zupełnie nowy byt. W ten sposób otrzymamy nasz pierwszy interfejs!
public interface Item {     
    
    public abstract void setName(String name);
    
    public abstract String getName();

    public abstract String getDescription();
} 
Możemy na tym poprzestać, ale tak naprawdę napisanie public abstract w przypadku interfejsów nic nie zmienia, gdyż domyślnie wszystkie metody interfejsów są już publiczne i abstrakcyjne (o ile nie oznaczymy inaczej). Tak więc najprostsza wersja takiego interfejsu może być zapisana tak:
public interface Item {     
    
    void setName(String name);
    
    String getName();

    String getDescription();
} 

Interfejs w Javie - Podstawowa definicja

Interfejs jest bytem z którego - podobnie jak z klasy abstrakcyjnej - nie można utworzyć instancji obiektu. Interfejsy posiadają następujące własności:
  • Oznaczamy je słowem interface.
  • Klasy mogą implementować interfejsy (a nie rozszerzać, tak jak było w przypadku klas). W tym celu używamy słowa implements zamiast extends:
    public class DocumentItem implements Item {
    
        ...
    } 
    
    public class MovieItem implements Item {
    
        ...
    } 
    
  • Implementując interfejs klasa musi dostarczyć ciało dla każdej z metod interfejsu (poza metodami domyślnymi, ale o tym za chwilę):
    public class DocumentItem implements Item {
    
        String name;       
        
        public void setName(String name) {
            this.name = name;
        }    
        
        public String getName() {
            return name;
        }
    
        public String getDescription() {
            return "This is description for DocumentItem";
        }
    } 
    
    public class MovieItem implements Item {
    
        String name;       
        
        public void setName(String name) {
            this.name = name;
        }    
        
        public String getName() {
            return name;
        }
    
        public String getDescription() {
            return "This is description for MovieItem";
        }
    } 
    
  • Klasa może implementować wiele interfejsów (rozszerzać mogła tylko jedną klasę):
    public class DocumentItem implements Item, Image {
    
        String name;       
        
        public void setName(String name) {
            this.name = name;
        }    
        
        public String getName() {
            return name;
        }
    
        public String getDescription() {
            return "This is description for DocumentItem";
        }
        
        public String getImageName() {
            return "DefaultImage.png";
        }
    } 
    
    public interface Image {     
        
        public String getImageName();    
    } 
    
  • Interfejs może rozszerzać inny interfejs (analogicznie do klasy rozszerzającej klasę):
    public interface Image extends Graphic {
    
        ...
    } 
    
    public interface Graphic {     
        
        ...
    } 
    
  • Poza metodami domyślnymi metody interfejsów nie mogą posiadać ciała.
  • Interfejsy nie posiadają konstruktorów.

Metody domyślne w interfejsach

Przez wiele długich lat było tak, że wszystkie metody interfejsów musiały być dostarczone w klasie implementującej dany interfejs. Innymi słowy, jeśli w kodzie naszego programu mieliśmy interfejs zaimplementowany na przykład przez 10 klas, dodanie metody do tego interfejsu powodowało, że wszystkie 10 klas musiało zostać zmienionych. Było to bardzo problematyczne i niekomfortowe zarazem. Często było tak, żę część klas implementujących dany interfejs nie potrzebowała nowej metody i zwykle tworzona była w nich wtedy pusta metoda, która nie robiła kompletnie nic.

Paradoksalni było to bardzo problematyczne dla twórców samej Javy, gdyż ograniczało zmiany w interfejsach działających od początku w Javie. Z tego powodu programiści języka wprowadzili możliwość dodawania do intefejsów metod zawierających ciało. Metody te używają słowa kluczowego default i są nazywane metodami domyślnymi. Jako, że są one od razu zaimplementowane (nie są abstrakcyjne), nie jest wymagane dostarczanie ich implementacji w klasach dziedziczących. W razie potrzeby mogą być one nadpisywane w tych klasach.
public interface Item {     
    
    public void setName(String name);
    
    public String getName();

    public String getDescription();
    
    default String getFullName() {
        return "Item in StartAPPa";
    }
} 

Stałe wartości w interfejsach

W Javie oprócz zmiennych możemy wprowadzić do kodu także wartości stałe. Będziemy jeszcze o tym mówić w przyszłości, ale na ta chwilę istotne jest aby wiedzieć, że stałą definiujemy za pomocą połączenia dwóch słów kluczowych static final. Dodatkowo nazwa stałej powinna być pisana dużymi literami (w razie nazwy złożonej z kilku członów - rozdzielamy je znakiem podkreślenia _):
public class MovieItem {     
    
    public static final String LABEL = "Default item name"; 

} 
Stałą wartość możemy zainicjować wartością tylko w trakcie tworzenia. Możemy to zrobić albo od razu w polu, albo w konstruktorze. Nie możemy później zmienić takiej wartości. Przypisanie nowej wartości zakończy się błędem kompilacji.
public class MovieItem {     

    public static final String LABEL = "Default item name"; 
    
    public void updateLabel() {
        this.LABEL = "Default item name created by JavAPPa"; //nie skompiluje się
    } 

} 
Co to wszystko ma wspólnego z interfejsami? Okazuje się, że w interfejsach również możemy tworzyć stałe, ale z tą różnicą, że są one deklarowane automatycznie i niejawnie. Tak więc nie wpisujemy w kodzie słów static final:
public interface Item {     

    public String LABEL = "Item of any Movie";
    
    public void setName(String name);
    
    public String getName();

    public String getDescription();
    
    default String getFullName() {
        return "Item in StartAPPa";
    }
} 
Taki zapis, mimo że wygląda na zmienną, tak naprawdę taką zmienną nie jest, gdyż w interfejsach taki zapis oznacza wartość stałą. W interefejsach nie możemy deklarować zmiennych w polach.

Inne metody w interfejsach

Interfejsy przez wiele lat mogły posiadać tylko metody publiczne abstrakcyjne. Od jakiegoś czasu, a konkretnie od Javy 8 i 9 trochę się w tym temacie pozmieniało i obecnie w interfejsach możemy używać również innych rodzajów metod, np. metody statyczne lub prywatne. Zajmiemy się tym szerzej już w następnym rozdziale.
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