Metody domyślne i statyczne w interfejsie
Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 37 z 87.
Pierwotnie interfejsy mogły zawierać wyłącznie metody abstrakcyjne bez implementacji. Począwszy od Java 8, interfejsy zyskały możliwość zawierania metod domyślnych i metod statycznych, co zwiększyło ich elastyczność.
Metoda domyślna zapewnia implementację bezpośrednio w interfejsie przy użyciu słowa kluczowego default. Klasy implementujące interfejs automatycznie dziedziczą to zachowanie, ale w razie potrzeby mogą je nadpisać:
public interface Drawable {
void draw();
default void display() {
System.out.println("Displaying on screen...");
draw();
}
}Każda klasa implementująca Drawable otrzymuje metodę display() za darmo. Jest to szczególnie przydatne przy dodawaniu nowych metod do istniejących interfejsów bez naruszania klas, które już je implementują.
Metody statyczne w interfejsach działają jak metody statyczne w klasach. Należą do samego interfejsu i są wywoływane przy użyciu nazwy interfejsu:
public interface MathOperations {
static int add(int a, int b) {
return a + b;
}
}
// Użycie
int result = MathOperations.add(5, 3);Statycznych metod interfejsu nie można przesłonić i nie są one dziedziczone przez klasy implementujące interfejs. Przydają się w przypadku metod pomocniczych związanych z przeznaczeniem interfejsu.
Jeśli klasa implementuje dwa interfejsy z taką samą sygnaturą metody domyślnej, klasa musi nadpisać tę metodę, aby rozwiązać konflikt.
Wyzwanie
ŁatwyZbudujmy system wiadomości, który pokazuje zarówno metody domyślne, jak i statyczne w interfejsach. Utworzysz interfejs z wbudowaną funkcjonalnością, z której klasy implementujące go mogą korzystać bezpośrednio lub którą mogą dostosować do swoich potrzeb.
Rozmieścisz kod w czterech plikach:
Messenger.java: Zdefiniuj interfejs reprezentujący dowolną usługę do wysyłania wiadomości. Powinien deklarować abstrakcyjną metodęsendMessage(String message), która zwraca void. Dodaj metodę domyślną o nazwiesendWithTimestamp(String message), która wyświetla:[TIMESTAMP], a następnie wywołujesendMessage(message). Uwzględnij też metodę statyczną o nazwieformatMessage(String message), która zwraca wiadomość zamienioną na wielkie litery.EmailMessenger.java: Utwórz klasę implementującąMessenger. Ma polerecipienttypu String. Dodaj konstruktor inicjujący odbiorcę. ZaimplementujsendMessage(), aby wyświetlała:Email to [recipient]: [message]. Ta klasa korzysta z domyślnej metodysendWithTimestamp()bez zmian.SMSMessenger.java: Utwórz kolejną klasę implementującąMessenger. Ma polephoneNumbertypu String. Dodaj konstruktor inicjujący numer telefonu. ZaimplementujsendMessage(), aby wyświetlała:SMS to [phoneNumber]: [message]. Nadpisz domyślną metodęsendWithTimestamp(), aby wyświetlała:[URGENT], a następnie wywoływałasendMessage(message)zamiast korzystać z domyślnego zachowania dodającego znacznik czasu.Main.java: Połącz wszystko, aby zaprezentować domyślne i statyczne metody interfejsu. Otrzymasz trzy dane wejściowe: odbiorcę wiadomości e-mail, numer telefonu i wiadomość. Najpierw użyj metody statycznejMessenger.formatMessage(), aby sformatować wiadomość i ją zapisać. Następnie utwórz obiekt EmailMessenger i obiekt SMSMessenger. Dla każdego z nich wywołajsendWithTimestamp()z sformatowaną wiadomością: zwróć uwagę, że EmailMessenger używa implementacji domyślnej, a SMSMessenger — jej nadpisanej wersji.
Otrzymasz trzy dane wejściowe: odbiorcę wiadomości e-mail (String), numer telefonu (String) i wiadomość (String).
Wynik powinien składać się łącznie z czterech wierszy: po dwa dla każdego obiektu do wysyłania wiadomości — wiersza z prefiksem ([TIMESTAMP] lub [URGENT]), a po nim wiersza z wiadomością. EmailMessenger wyświetli domyślny prefiks znacznika czasu, a SMSMessenger — własny, pilny prefiks. W obu przypadkach wiadomość będzie sformatowana statycznie (zapisana wielkimi literami)!
Spróbuj swoich sił
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Wczytaj dane wejściowe
String emailRecipient = scanner.nextLine();
String phoneNumber = scanner.nextLine();
String message = scanner.nextLine();
// TODO: Użyj Messenger.formatMessage(), aby sformatować wiadomość i ją zapisać
// TODO: Utwórz EmailMessenger z adresem e-mail odbiorcy
// TODO: Utwórz SMSMessenger z numerem telefonu
// TODO: Wywołaj sendWithTimestamp() na EmailMessenger, przekazując sformatowaną wiadomość
// TODO: Wywołaj sendWithTimestamp() na SMSMessenger, przekazując sformatowaną wiadomość
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe thisMetodyPola (atrybuty)Metoda konstruktoraPrzeciążanie konstruktoraPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawy dziedziczenia (extends)Słowo kluczowe superPrzesłanianie metod (@Override)Łańcuch wywołań konstruktorówKlasa ObjectDziedziczenie jedno- i wielopoziomoweDlaczego Java nie obsługuje wielodziedziczenia klasPodsumowanie – hierarchia pracowników7Metody specjalne i klasa Object
Metoda toString()equals() i hashCode()Metoda clone()compareTo() i ComparableInterfejs ComparatorPodsumowanie — własne sortowanie10Obsługa wyjątków w programowaniu obiektowym
Hierarchia klas wyjątkówWłasne wyjątkiBłędy sprawdzane a niesprawdzaneWzorzec try-with-resourcesPodsumowanie – zweryfikowany użytkownik2Modyfikatory dostępu i enkapsulacja
Przegląd poziomów dostępuMetody pobierające i ustawiająceUkrywanie informacjiSłowo kluczowe finalPodsumowanie — menedżer kont bankowych5Polimorfizm
Podstawy przeciążania metodPrzesłanianie metod (w czasie wykonywania)Rzutowanie w górę i w dółOperator instanceofKlasy i metody abstrakcyjnePowtórka — kalkulator figur8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieAgregacja a kompozycjaKlasy wewnętrzne, zagnieżdżone i anonimoweEnumy i metody enumówRekordy (Java 16+)Klasy zapieczętowane (Java 17+)11Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec BuilderWzorzec ObserverWzorzec Strategy3Właściwości klas i składowe statyczne
Zmienne instancji a zmienne statyczneMetody statyczneBloki statyczneStałe (static final)Powtórka – Counter i Utility6Interfejsy i klasy abstrakcyjne
Wprowadzenie do interfejsówImplementowanie interfejsówImplementacja wielu interfejsówMetody domyślne i statyczne w interfejsieKlasy abstrakcyjne a interfejsyInterfejsy funkcyjnePodsumowanie — system płatnościPoćwicz samodzielnie: Kompilator Java online