Dawniej interfejsy mogły zawierać wyłącznie metody, które z założenia były public
i
abstract
. Metody interfejsu określały jakie operacje ma wykonywać klasa implementująca, ale nie określały sposobu, w jaki te operacje będą wykonywane. Nie jest to już prawdą.
Metody domyślne w interfejsach
Od Java 8 w interfejsach obok metod abstrakcyjnych można umieszczać metody oznaczone słowem kluczowym default
, umieszczanym przed nazwą typu zwracanego przez metodę. Metody te z założenia są public
. Metody te zawierają kod określający, nie tylko co ma być wykonywane, ale również jak te operacje mają być wykonane. Są to więc pełne metody. Klasa implementująca interfejs przejmuje te metody.
NType
interface NType { default int amod(int index, int modulus) { int i = index; i = i % modulus; if(i == 0){ i = modulus; } if(i < 0){ i = (modulus + i); } return i; } }
W interfejsie znalazła się metoda amod()
oznaczona słowem kluczowym default
. Teraz możemy jej użyć w klasie Liczba
implementującej ten interfejs:
Liczba liczba = new Liczba(); System.out.println(liczba.amod(32, 12));
Operator amod
podobny jest do operatora %. Rożni się od tego w Javie tym, że 1) w przypadku gdy wynik index%modulus == 0
zwraca nie 0
, ale modulus, 2) gdy wynik index%modulus<0
zwraca nie liczbę ujemną, ale wynik powiększony o modulus.
Metoda amod()
zachowuje się dokładnie tak jak zachowywała się gdyby była umieszczona w klasie Liczba.
Dodawanie metod domyślnych do istniejących interfejsów
Do Javy 8 umieszczenie nowej metody w interfejsie powodowało automatycznie konieczność dodania implementacji tej metody we wszystkich klasach implementujących interfejs lub dodania słowa kluczowego abstract
do tych klas.
W Java 8 dodanie do interfejsu metody oznaczonej jako default
nie powoduje konieczności dokonywania jakichkolwiek zmian w istniejącym kodzie klas implementujących ten interfejs. Po prostu metoda staje się automatycznie dostępna dla wszystkich klas.
Oczywiście metodę możemy przesłonić w klasie implementującej, jeżeli zajdzie taka potrzeba.
W interfejsie możemy umieścić dowolną liczbę metod domyślnych.
Metody statyczne w interfejsach
Kiedyś metody statyczne mogły być gromadzone w klasach zawierających prywatny konstruktor. Przykładem takiej niewielkiej klasy jest klasa ColorUtil
.
Obecnie nie ma potrzeby używania takich klasy. Metody można bezpośrednio przenieść do interfejsu:
ColorUtil2
interface ColorUtil2 { public static String HexToRGB(String hexa) { Integer R = Integer.valueOf(hexa.substring(0, 2), 16); Integer G = Integer.valueOf(hexa.substring(2, 4), 16); Integer B = Integer.valueOf(hexa.substring(4, 6), 16); return ("RGB:[" + R + "," + G + "," + B + "]"); } ...
Metod statycznych umieszczonych w interfejsie używamy identycznie jak metod umieszczonych w klasie z prywatnym konstruktorem
ColorUtilTest1
System.out.println(ColorUtil.RGBToHex(25, 50, 75)); System.out.println(ColorUtil2.RGBToHex(25, 50, 75));
Wynik jest w obu przypadkach jednakowy:
0x19324b 0x19324b
W interfejsie możemy umieścić dowolną liczbę metod statycznych. Słowa kluczowe static
i default
w metodach domyślnych i statycznych wykluczają się wzajemnie, gdyż oczywiście metody default
są metodami instancji (ColorUtil3
), a metody static
są metodami klasy (ColorUtil2
):
ColorUtilTest2
System.out.println(ColorUtil2.RGBToHex(25, 50, 75)); //System.out.println(ColorUtil3.RGBToHex(25, 50, 75));//błąd Test2 t = new Test2(); System.out.println(t.RGBToHex(25, 50, 75));
Interfejsy funkcyjne i metody funkcyjne
W Javie 8 zwykłe interfejsy zawierające wyłącznie jedną metodę abstrakcyjną zostały nazwane interfejsami funkcyjnymi. Taka metoda w interfejsie została nazwana metodą funkcyjną. Taki i wyłącznie taki typ interfejsu pozwala na używanie go w tzw. wyrażeniach funkcyjnych lambda. Interfejsy funkcyjne poza metodą funkcyjną mogą zawierać metody domyślne i statyczne.
Interfejs IType<T>
jest przykładem interfejsu funkcyjnego:
IType
public interface IType<T> { boolean equals(T x, T y); }
Przykładem interfejsu funkcyjnego, który istnieje w języku Java od dawna jest na przykład Runnable
zawierający jedną metodę run()
, a także Comparator
z metodą compareTo()
czy ActionListener
z metodą actionPerformed
.
Metody anonimowe
Najczęstszym wykorzystaniem powyższych (i innych) interfejsów funkcyjnych jest implementacja metody funkcyjnej przez utworzenie klasy anonimowej. W Java 8 stworzono pojęcie anonimowych metod, tworzonych przez programistę, które przez kompilator zamieniane są automatycznie na odpowiednie anonimowe klasy wewnętrzne.
Pliki do ściągnięcia