OK, to może mały przykład jeszcze.
Załóżmy, że mamy abstrakcyjną klasę Vechicle, która ma pewne typowe dla pojazdów własności enginePower, maxSpeed itp. Rozszerza ją klasa FlyingVechicle w klasycznym modelu dziedziczenia powiemy FlyingVechicle is a Vechicle czyli jest typu Vechicle Teraz anlogicznie mamy rodzinę klas z bazową klasą Animal, która ma zupełnie inne właściwości niż obiekty klasy Vechicle i próbowanie łączenia pojazdów i zwierząt w hierachie klas w sposób oczywisty jest niemożliwe, tudzież prowadzi to katastrofy.
Z klasy Animal dziedziczy dlaej FlyingAnimal, znowu powiemy FlyingAnimal is an Animal.
Obiekty typu FlyingAnimal i FlyingVechicle mają jednak jedną wspólną cechę - latają (poz tym nic je nie łączy). Teraz powiedzmy, że chcielibyśmy żeby te latające obiekty miały ze sobą coś wspólnego. Z pomocą przychodzą tu interfejsy. Zróbmy sobie interfejs Flyable, który zaimplementujemy w naszych latających klasach FlyingAnimal i FlyingVechicle.
Kopiuj
public interface Flyable {
default void fly(){
System.out.println("fly baby");
}
}
Interfejs to umowa, mówi do swojego klienta - "masz latać", a klient mówi "ok będę latał, umowa stoi."
W naszych klasach możemy przedefniować metodę fly, albo zostawić ją domyślną tj bez konieczności implementacji.
Ponieważ interfejs jest również typem nadrzędnym, dla klas, które go implementują zatem możemy to wykorzystać i na przykład zrobić sobie kolekcję typu Flyable.
Kopiuj
FlyingAnimal flyinAnimal= new FlyingAnimal();
FlyingVechicle flyingVechicle = new FlyingVechicle();
List<Flyable> flyables = new ArrayList<>();
flyables.add(flyingVechicle);
flyables.add(flyinAnimal);
//latajcie
flyables.forEach(f -> f.fly());