Każda nowa wersja Javy różni się od poprzednich. Oto przykład zmian w stosunku do materiału, przez który przechodziliśmy: Przed Javą 5
Tak więc Java 8 różni się zauważalnie od Javy 7. Oczywiście nie będziemy ignorować ważnych innowacji. Ponieważ w tym wykładzie mówimy o interfejsach, rozważymy jedną aktualizację - domyślne metody w interfejsach . Wiesz już, że interfejs nie implementuje zachowania . Jego zadaniem jest opisanie, jakie zachowanie powinny mieć wszystkie obiekty, które go implementują . Ale dość często programiści spotykali się z sytuacjami, w których implementacja metody we wszystkich klasach była taka sama. Spójrzmy na przykład naszego starego samochodu:
enums
w języku nie było „.
public interface Car {
public void gas();
public void brake();
}
public class Sedan implements Car {
@Override
public void gas() {
System.out.println("Gas!");
}
@Override
public void brake() {
System.out.println("Brake!");
}
}
public class Truck implements Car {
@Override
public void go() {
System.out.println("Gas!");
}
@Override
public void brake() {
System.out.println("Brake!");
}
}
public class F1Car implements Car {
@Override
public void go() {
System.out.println("Gas!");
}
@Override
public void brake() {
System.out.println("Brake!");
}
}
Jak myślisz, jaki jest główny problem z tym kodem? Pewnie zauważyłeś, że napisaliśmy sporo tego samego kodu! Ten problem jest powszechny w programowaniu i należy go unikać. Inna sprawa, że przed wydaniem Javy 8 nie było specjalnych rozwiązań. Kiedy pojawiła się ta wersja, stało się możliwe definiowanie domyślnych metod i implementowanie ich bezpośrednio w interfejsie! Oto jak to się robi:
public interface Car {
public default void gas() {
System.out.println("Gas!");
}
public default void brake() {
System.out.println("Brake!");
}
}
public class Sedan implements Car {
}
public class Truck implements Car {
}
public class F1Car implements Car {
}
Teraz metody gas()
i brake()
, które były takie same dla wszystkich maszyn, zostały przeniesione do interfejsu, a powtarzany kod nie jest potrzebny. Co więcej, w każdym z zajęć dostępne są metody!
public class Main {
public static void main(String[] args) {
F1Car f1Car = new F1Car();
Sedan sedan = new Sedan();
Truck truck = new Truck();
truck.gas();
sedan.gas();
f1Car.brake();
}
}
Co jeśli istnieje 100 klas z metodą, gas()
ale tylko 99 z nich zachowuje się tak samo? Wszystko psuje, a domyślna metoda nie zadziała w tym przypadku? Oczywiście, że nie :) Domyślne metody interfejsów można nadpisać.
public class UnusualCar implements Car {
@Override
public void go() {
System.out.println("This car accelerates differently!");
}
@Override
public void brake() {
System.out.println("This car slows down differently!");
}
}
Wszystkie pozostałe 99 typów maszyn zaimplementuje metodę domyślną i klasęUnusualCar
- wyjątek - nie psuje całości obrazu i spokojnie determinuje jego zachowanie. Wielokrotne dziedziczenie w interfejsach Jak już wiesz, w Javie nie ma wielokrotnego dziedziczenia. Jest tego wiele powodów, rozważymy je szczegółowo w osobnym wykładzie. W innych językach, na przykład w C++, jest odwrotnie. Bez wielokrotnego dziedziczenia pojawia się poważny problem: ten sam obiekt może mieć wiele różnych cech i „zachowań”. Przykład z życia: dla rodziców jesteśmy dziećmi, dla nauczycieli uczniami, dla lekarzy pacjentami. W życiu pojawiamy się w różnych rolach iw związku z tym inaczej się zachowujemy: z nauczycielami oczywiście będziemy rozmawiać inaczej niż z bliskimi przyjaciółmi. Spróbujmy przełożyć tę sytuację na kod. Wyobraźmy sobie, że mamy dwie klasy: Pond i Aviary. Staw potrzebuje pływających ptaków, a dla lotnictwa - latanie. W tym celu stworzyliśmy dwie klasy bazowe −FlyingBird
i Waterfowl
.
public class Waterfowl {
}
public class FlyingBird {
}
W związku z tym wyślemy do FlyingBird
stawu te ptaki, których klasy są odziedziczone po , i te, które pochodzą z Waterfowl
. Wszystko wydaje się proste. Ale co zrobimy, jeśli będziemy musieli gdzieś zdefiniować kaczkę? Ona pływa i lata. Nie mamy wielokrotnego dziedziczenia. Na szczęście Java zapewnia wiele implementacji interfejsów. Jeśli klasa nie może dziedziczyć po wielu rodzicach, implementacja wielu interfejsów jest łatwa! Nasza kaczka potrafi zarówno latać, jak i pływać :) Wystarczy zrobić FlyingBird
nie Waterfowl
z klasami, ale z interfejsami, aby osiągnąć zamierzony efekt.
public class Duck implements FlyingBird, Waterfowl {
// Methods of both interfaces combine easily into one class
@Override
public void fly() {
System.out.println("Flying!");
}
@Override
public void swim() {
System.out.println("Swimming!");
}
}
Dzięki temu nasz program zachowuje elastyczne zarządzanie klasami, a w połączeniu z implementacją metod domyślnych nasze możliwości określania zachowania obiektów stają się niemal nieograniczone! :)
GO TO FULL VERSION