Lekcje modułu (1/2)
Interfejsy
Podczas gdy klasy abstrakcyjne mogą zawierać zarówno częściowo zaimplementowany kod, jak i pola instancji, interfejsy w Javie są kontraktami czystego zachowania. Interfejs definiuje co klasa musi umieć zrobić, ale nie jak to robi.
Pozwala to na całkowite uniezależnienie definicji operacji od ich rzeczywistej implementacji.
Definiowanie interfejsu (interface)
Używa się słowa kluczowego interface. Wszystkie metody zadeklarowane w interfejsie są implikowanie public i abstract (nie ma potrzeby tego określać):
interface Drivable {
void startEngine();
void stopEngine();
}
Implementowanie interfejsu (implements)
Klasa implementuje interfejs za pomocą słowa kluczowego implements i jest zobowiązana do dostarczenia implementacji (z ciałem) dla wszystkich zdefiniowanych metod:
class Motorcycle implements Drivable {
@Override
public void startEngine() {
System.out.println("Rombo del motore acceso!");
}
@Override
public void stopEngine() {
System.out.println("Motore spento.");
}
}
Zalety interfejsów
- Wielokrotne dziedziczenie: W Javie klasa może rozszerzać tylko jedną klasę nadrzędną (dziedziczenie pojedyncze), ale może implementować wiele interfejsów jednocześnie.
Code
class HybridCar implements Drivable, Chargeable { ... } - Luźne powiązanie (Desacoplamiento): Możesz definiować zmienne przy użyciu typu interfejsu. Dowolny obiekt implementujący ten interfejs może zostać przypisany do tej zmiennej.
Code
Drivable vehicle = new Motorcycle(); vehicle.startEngine();
Stałe w interfejsach
W interfejsach możliwe jest deklarowanie pól. Pola te są implikowanie public static final (czyli stałymi klasowymi), nawet jeśli nie określimy tych modyfikatorów. W związku z tym muszą być zainicjalizowane natychmiast w momencie deklaracji:
interface PhysicsConstants {
double GRAVITY = 9.81; // Implicitamente public static final
}
Metody domyślne (default)
Począwszy od Javy 8, możliwe jest definiowanie metod z domyślną implementacją wewnątrz interfejsu za pomocą słowa kluczowego default. Metody te nie zmuszają klas implementujących interfejs do ich nadpisywania, zapewniając zachowanie awaryjne (fallback):
interface Logger {
void log(String message);
// Metodo di default con corpo
default void logError(String message) {
log("ERRORE: " + message);
}
}
Spróbuj sam
Utwórz interfejs Flyable z metodą void fly(). Następnie zaimplementuj klasę Bird tak, aby implementowała Flyable i wypisywała Flying na ekranie.
Pokaż wskazówkę
W Flyable wpisz `void fly();`. W klasie Bird zaimplementuj metodę, oznaczając ją `@Override public void fly() { System.out.println('Flying'); }`.
Rozwiązanie dostępne po 3 próbach
Zdefiniuj interfejs Drawable z metodą void draw(). Następnie zaimplementuj klasę Rectangle tak, aby implementowała Drawable i wypisywała Drawing Rectangle.
Pokaż wskazówkę
Zdefiniuj `void draw();` w interfejsie. W Rectangle użyj `@Override public void draw() { System.out.println('Drawing Rectangle'); }`.
Rozwiązanie dostępne po 3 próbach
Uzupełnij interfejs Swimmable, definiując metodę void swim(). Następnie uzupełnij klasę Duck tak, aby implementowała zarówno Flyable, jak i Swimmable, wypisując Flying w metodzie fly() i Swimming w metodzie swim().
Pokaż wskazówkę
Zadeklaruj `void swim();` w Swimmable. Zadeklaruj `class Duck implements Flyable, Swimmable` i zaimplementuj obie metody wypisując wymagane ciągi znaków.
Rozwiązanie dostępne po 3 próbach