#Praktyczna Java. Interfejsy, metody domyślne i klasy abstrakcyjne

By 5 października 2015Praktyczna Java

W #main z 28 września pytaliśmy o różnice pomiędzy interfejsem i klasą abstrakcyjną – w czasach Javy 7 odpowiedź ta miałaby jedno zdanie i nie ‚zasłużyła by’ na osobny wpis. Java 8 zmieniła jednak sytuacje diametralnie – zachęcamy do lektury!

Klasy abstrakcyjne

W klasach abstrakcyjnych nie zmieniły się założenia w Javie 8 – klasa abstrakcyjna to taka klasa, która może mieć metody abstrakcyjne. Za moment wyjaśnimy sobie czym są owe metody dokładnie, ale jeszcze parę słów o klasach abstrakcyjnych – poza powyższym rządzą się prawie tymi samymi prawami, co zwykłe klasy – mogą dziedziczyć po innych, można po nich dziedziczyć i mogą mieć normalne metody oraz implementować interfejsy. Jedyne różnice związane z tym, że są one abstrakcyjne to takie, że nie możemy utworzyć obiektu tego typu oraz klasa nie może być jednocześnie abstract i final.

Metody abstrakcyjne są bardzo podobne do zwykłych metod interfejsów – zawierają jedynie sygnaturę metody, bez jej ciała. Oznacza to, że klasy dziedziczące muszą ‚określić’ ciało tej metody (po prostu ją przesłaniając) lub same muszą być wtedy zadeklarowane jako abstrakcyjne. Przykładowa klasa abstrakcyjna wygląda następująco:

public abstract class AbstractClass {
    public void saySomething() {
        System.out.println("Something");
    }

    public abstract void saySomethingUsefull();
}

Co ważne, klasa abstrakcyjna wcale nie musi mieć metod abstrakcyjnych! Może to być sposób na zablokowanie tworzenia instancji danej klasy, jak na poniższym przykładzie:

public abstract class BaseService {
    protected String toJsonString() {
        //...
    }

    protected String innaMetodaPomocnicza() {
        //...
    }
}

Interfejsy

Interfejsy w Javie 7 były pewnego rodzaju zbiorem sygnatur metod, bez ciała. Od klas abstrakcyjnych odróżniało je to, że nie mogły mieć ciała metod, dozwolone było za to wielokrotne dziedziczenie.

Java 8 wprowadza nowość w interfejsach, a dokładniej metody domyślne. Metody domyślne pozwalają zdefiniować ciało metody w interfejsie. Co więcej, zachowujemy możliwość wielokrotnego dziedziczenia!

Tutaj zastrzeżenie – ta nowa cecha języka może być bardzo łatwo nadużywana i nie powinna być stosowana do implementacji wielokrotnego dziedziczenia w Javie – nie do tego służy i nie powinna być do tego stosowana. Korzystanie z metod domyślnych może też wprowadzić zamęt wśród osób rozwijających Twój kod w przyszłości. Polecamy mail na grupie Javy, którego autorem jest Brian Goetz, jeden z architektów samej Javy – wprawdzie odpowiada on na specyficzne pytanie, bardzo dobrze opisuje cel i ideę metod domyślnych.

Przykładowy interfejs z metodą domyślną wygląda następująco:

public interface Prioritized {
    public default int getPriority() {
        return 0;
    }
}

Pozwala on stosować ten interfejs jako ‚marker’, bez konieczności implementacji metody, która w większości przypadków wyglądałaby identycznie.

Zastrzeżenie: o ile powyższy fragment jest zgodny z celem, w jakim metody domyślne powstały, do określania priorytetów obiektów znacznie lepszym pomysłem jest skorzystanie z interfejsów, które już istnieją, jak Comparable czy Ordered (w Springu)

Mówiąc o metodach domyślnych warto poruszyć kolejną ważną rzecz – o ile Java dopuszcza wielokrotne dziedziczenie interfejsów, i jest to możliwe także z metodami domyślnymi, to w sytuacji konfliktu (dwa interfejsy posiadające metodę domyślną) wystąpi błąd kompilacji. Metody domyślne nie mogą też przysłaniać metod obiektów – metoda obiektu zawsze ‚wygrywa’ z metodą domyślną i to ona (metoda obiektu) jest uruchamiana.

Podsumowanie – jaka jest zatem różnica

Podsumowując, klasy abstrakcyjne mogą dziedziczyć tylko po jednej innej klasie, mogą dostarczać ciała metod i mogą określać metody o innej widoczności niż ‚public’. Interfejsy z kolei mogą być dziedziczone wielokrotnie, mogą dostarczać domyślne ciała metod (ale nie mogą przesłaniać innych metod) i dotyczą tylko metod o widoczności public.

Jak widzisz, odpowiedź na pytanie o różnice pomiędzy klasą abstrakcyjną a interfejsem nie jest już tak prosta ;) Warto o tym wiedzieć, jednak odradzam programowanie za pomocą metod domyślnych – możemy pewne elementy do nich ‚wyciągnąć’ już po napisaniu kodu, jako upiększenie i uproszczenie kodu, co pozwoli zminimalizować ryzyko nadużycia, ale nigdy, przenigdy nie stosuj tej cechy języka do obejścia problemów z projektem aplikacji i hierarchii klas!

Po bardziej szczegółowy opis odsyłamy do tutorialu Oracle.

  •  
  •  
  •  
  •  
  •  
  • jane

    Twoj blog jest napisany strasznie nieciekawie. Niby taki popularny a tak naprawdę ile osob po nim coś osiągnęło? mało kobiet zapewne, gdyż jest napisanym ciężkim językiem, którym się jak widać wzorowałaś z profesjonalnych stron. A szkoda. Po przeczytaniu tego artykułu dalej nie wiem jaka jest różnica, a głupia nie jestem. Pozdrawiam.j

    • Cześć, dzięki za komentarz :)
      zdajemy sobie sprawę, że nie każdemu musi odpowiadać sposób, w jaki staramy się przekazać wiedzę, w końcu każdy inaczej się uczy i przyswaja wiedzę. Niemniej z komentarzy i rozmów wynika że przynajmniej niektórym taki sposób jednak pasuje i jest efektywny :)
      To także super okazja – jeśli znasz sposób, żeby od innej strony opisać temat, zrób to – z przyjemnością podlinkujemy do Twojego tekstu. W końcu chodzi o to, żeby dzielić się wiedzą, prawda?

    • Marek Kopeć

      Nie rozumiem trochę czego w np. tym artykule można nie zrozumieć. Można mieć co do tego bloga pretensje że nie wyczerpuję tematu ale jest on stale rozwijany i jest nastawiony na zdobycie pierwszej pracy, nie akademizuje pewnych tematów, a podejście jest praktyczne.

    • MichałO

      jane wybacz ale pewnych rzeczy w obiektowości nie da się uprościć.Trzeba dużo praktyki,przerabiania mnóstwa przykładów by dobrze zrozumieć temat.

  • wBacz

    lepiej nauczcie isę dobrze gotować, by Wasi mężowie dobrze programowali.

  • name

    serio, niby spoko blog, ale niektore rzeczy jakby przetłumaczone jakby z profesjonalnych ksiazek. słabo troche.

    • Seria #PraktycznaJava, jest przeznaczona dla osób mających opanowane podstawy, stąd inny sposób pisania. Na pewno jednak daleko nam od tłumaczenia dosłownie dokumentacji z angielskiego na polski ;).

  • Wiktor Kalinowski

    Aby zrozumieć ten wpis trzeba już mieć opanowane podstawy. :)

    • Oj tak, dlatego jest z serii Praktyczna Java, która jest przeznaczona dla osób znających już podstawy. Przystępniejsze treści są w Kusie Javy czy Niezbędniku Juniora.

  • Dawid Śremski

    Dzięki :) Właśnie rozwiały się moje wątpliwości co do tego czy stosowanie metod defaultowych to dobra praktyka :)