Kiedy używać: Java 8+ interface default method, vs. abstract method

Java 8 pozwala na domyślną implementację metod w interfejsach o nazwie Default Methods.

Jestem zdezorientowany, kiedy użyłbym tego rodzaju interface default method, zamiast abstract class (z abstract method(s)).

Kiedy należy używać interfejsu z domyślnymi metodami, a kiedy klasy abstrakcyjne(z abstrakcyjnymi metodami)? Czy klasy abstrakcyjne są nadal przydatne w tym scenariuszu?

Author: cellepo, 2013-11-15

15 answers

W klasach abstrakcyjnych jest o wiele więcej niż domyślne implementacje metod (takie jak private state), ale począwszy od Javy 8, gdy masz wybór jednej z nich, powinieneś użyć defender (aka. default) metoda w interfejsie.

Ograniczenie domyślnej metody polega na tym, że może być zaimplementowana tylko w zakresie wywołań do innych metod interfejsu, bez odniesienia do określonego stanu implementacji. Tak więc głównym przypadkiem użycia jest wyższy poziom i wygoda metody.

Dobrą rzeczą w tej nowej funkcji jest to, że, gdzie wcześniej był zmuszony do korzystania z abstrakcyjnej klasy dla metod wygody, ograniczając w ten sposób implementatora do pojedynczego dziedziczenia, teraz możesz mieć naprawdę czysty projekt tylko z interfejsem i minimum wysiłku implementacji wymuszonego na programiście.

Pierwotną motywacją do wprowadzenia metod default do Javy 8 była chęć rozszerzenia interfejsów frameworku zbiorów o metody zorientowane na lambda bez przerywania istniejących implementacji. Chociaż jest to bardziej istotne dla autorów bibliotek publicznych, ta sama funkcja może być przydatna również w Twoim projekcie. Masz jedno scentralizowane miejsce, w którym możesz dodać nową wygodę i nie musisz polegać na tym, jak wygląda reszta hierarchii typów.

 327
Author: Marko Topolnik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-10 06:41:00

Istnieje kilka różnic technicznych. Klasy abstrakcyjne mogą zrobić więcej w porównaniu z interfejsami Java 8:

  1. klasa abstrakcyjna może mieć konstruktor.
  2. klasy abstrakcyjne są bardziej uporządkowane i mogą posiadać stan.

Koncepcyjnie głównym celem metod defender jest wsteczna kompatybilność po wprowadzeniu nowych funkcji (jako lambda-functions) w Javie 8.

 138
Author: Vadym Vasyliev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-15 10:21:48

Jest to opisane w tym Artykuł . Pomyśl o forEach o zbiorach.

List<?> list = …
list.forEach(…);

ForEach nie jest deklarowany przez java.util.List ani przez java.util.Collection Interfejs jeszcze. Jednym z oczywistych rozwiązań byłoby wystarczy dodać nową metodę do istniejącego interfejsu i dostarczyć wdrożenie tam, gdzie jest to wymagane w JDK. Jednak po opublikowaniu jest niemożliwe, aby dodać metody do interfejsu bez łamania istniejące wdrożenie.

The benefit that default metody przynoszą, że teraz Można Dodaj nową domyślną metodę do interfejsu i nie złamie wdrożenia.

 66
Author: Masudul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-15 10:15:55

Jak opisano w Niniejszym artykule,

Klasy abstrakcyjne a interfejsy w Javie 8

Po wprowadzeniu metody domyślnej wydaje się, że interfejsy i klasy abstrakcyjne są takie same. Jednak nadal są one inne pojęcie w Javie 8.

Klasa abstrakcyjna może zdefiniować konstruktor. Są bardziej ustrukturyzowane i mogą mieć Państwo z nimi związane. Natomiast w kontraście domyślne metoda może być zaimplementowana tylko w zakresie wywoływania innych metody interfejsu, bez odniesienia do konkretnej implementacji stan. Dlatego zarówno używać do różnych celów, jak i wybierać pomiędzy dwoma naprawdę zależy od kontekstu scenariusza.

 27
Author: Sufiyan Ghori,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-08 01:00:37

Te dwa są całkiem różne:

Domyślnymi metodami są Dodawanie zewnętrznej funkcjonalności do istniejących klas bez zmiany ich stanu.

I klasy abstrakcyjne są normalnym typem dziedziczenia, są klasami normalnymi , które mają zostać rozszerzone.

 19
Author: Andrey Chaschev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-15 10:31:44

Odnośnie Twojego zapytania o

Kiedy należy używać interfejsu z domyślnymi metodami, a kiedy klasy abstrakcyjne? Czy klasy abstrakcyjne są nadal przydatne w tym scenariuszu?

Java dokumentacja zapewnia doskonałą odpowiedź.

Klasy abstrakcyjne w porównaniu do interfejsów:

Klasy abstrakcyjne są podobne do interfejsów. Nie można utworzyć ich instancji i mogą one zawierać kombinację metod zadeklarowanych z lub bez wdrożenie.

Jednak za pomocą klas abstrakcyjnych można deklarować pola, które nie są statyczne i ostateczne, a także definiować konkretne metody publiczne, chronione i prywatne.

W przypadku interfejsów wszystkie pola są automatycznie publiczne, statyczne i końcowe, a wszystkie metody deklarowane lub definiowane (jako metody domyślne) są publiczne. Ponadto można rozszerzyć tylko jedną klasę, niezależnie od tego, czy jest ona abstrakcyjna, czy nie, podczas gdy można zaimplementować dowolną liczbę interfejsów.

Przypadki użycia dla każdego z zostały one wyjaśnione w poniższym poście SE:

Jaka jest różnica między interfejsem a klasą abstrakcyjną?

Czy klasy abstrakcyjne są nadal przydatne w tym scenariuszu?

Tak. Nadal są przydatne. Mogą one zawierać niestatyczne, niekończące się metody oraz atrybuty (chronione, prywatne oprócz publicznych), co nie jest możliwe nawet w przypadku interfejsów Java-8.

 15
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Kiedy mamy wybór pomiędzy klasą abstrakcyjną a interfejsem, zawsze powinniśmy (prawie) preferować metody domyślne (znane również jako defender lub virtual extensions).

  1. Domyślne metody położyły kres klasycznemu wzorcowi interfejsu i klasie towarzyszącej, która implementuje większość lub wszystkie metody w tym interfejsie. Przykładem jest Collection and AbstractCollection. Teraz powinniśmy zaimplementować metody w samym interfejsie, aby zapewnić domyślną funkcjonalność. Klasy, które implementują interfejs ma możliwość nadpisania metod lub dziedziczenia domyślnej implementacji.

  2. Innym ważnym zastosowaniem metod domyślnych jest interface evolution. Załóżmy, że miałem piłkę klasową jako:

    public class Ball implements Collection { ... }

Teraz w Javie 8 pojawiła się nowa funkcja. Możemy uzyskać strumień używając metody stream dodanej do interfejsu. Gdyby {[3] } nie była domyślną metodą, wszystkie implementacje interfejsu Collection zostałyby złamane, ponieważ nie implementowałyby tej nowej metody. Dodawanie domyślną metodą interfejsu nie jest source-compatible.

Ale załóżmy, że nie przekompilujemy klasy i nie użyjemy starego pliku jar, który zawiera tę klasę Ball. Klasa będzie ładować się dobrze bez tej brakującej metody, instancje mogą być tworzone i wydaje się, że wszystko działa dobrze. ale jeśli program wywoła metodę stream Na instancji Ball otrzymamy AbstractMethodError. Tak więc dokonywanie metody domyślnej rozwiązało oba problemy.

Java 9 ma nawet prywatne metody w interfejsie który może być użyty do hermetyzacji wspólnej logiki kodu, która była używana w metodach interfejsu, które zapewniały domyślną implementację.

 15
Author: akhil_mittal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-18 02:54:28

Chociaż to stare pytanie pozwól mi dać swój wkład w nim, jak również.

  1. klasa abstrakcyjna: wewnątrz klasy abstrakcyjnej możemy zadeklarować instancję zmienne, które są wymagane do klasy potomnej

    Interface: wewnątrz interfejsu każda zmienna jest zawsze public static and final we cannot declare instance variables

  2. klasa abstrakcyjna: klasa abstrakcyjna może mówić o stanie obiektu

    interfejs: interfejs może nigdy nie mów o stanie obiektu

  3. klasa abstrakcyjna: wewnątrz klasy abstrakcyjnej możemy zadeklarować konstruktory

    Interface: wewnątrz interfejsu nie możemy zadeklarować konstruktorów jako celu
    konstruktory służą do inicjalizacji zmiennych instancji. Co z tego? jest potrzeba konstruktora, jeśli nie możemy mieć instancji zmienne w interfejsach .

  4. klasa abstrakcyjna: wewnątrz klasy abstrakcyjnej możemy zadeklarować instancję i statykę bloki

    interfejs: Interfejsy nie mogą mieć bloków instancyjnych i statycznych.

  5. klasa abstrakcyjna: klasa abstrakcyjna nie może odwoływać się do wyrażenia lambda

    interfejsy: Interfejsy z pojedynczą abstrakcyjną metodą mogą odnosić się do wyrażenia lambda

  6. klasa abstrakcyjna : wewnątrz klasy abstrakcyjnej możemy nadpisać metody klasy obiektowej

    interfejsy: nie możemy nadpisać metod klasy obiektu wewnątrz interfejsy.

Na koniec dodam, że:

Domyślne koncepcje metod / statyczne koncepcje metod w interfejsie pojawiły się tylko po to, aby zapisać klasy implementacji, ale nie po to, aby zapewnić sensowną użyteczną implementację. Domyślne metody / metody statyczne są rodzajem atrapy implementacji, "jeśli chcesz, możesz je użyć lub możesz je nadpisać (w przypadku metod domyślnych) w klasie implementacji" , co pozwala nam zaoszczędzić od implementacji nowych metod w klasach implementacji ilekroć dodawane są nowe metody w interfejsach. dlatego interfejsy nigdy nie mogą być równe klasom abstrakcyjnym.

 13
Author: Umar Tahir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-18 16:50:31

Domyślne metody w interfejsie Java umożliwiają ewolucję interfejsu .

Biorąc pod uwagę istniejący interfejs, jeśli chcesz dodać do niego metodę bez naruszania kompatybilności binarnej ze starszymi wersjami interfejsu, masz dwie opcje: Dodaj metodę domyślną lub statyczną. Każda abstrakcyjna metoda dodana do interfejsu musiałaby być zaimplementowana przez klasy lub Interfejsy implementujące ten interfejs.

Statyczna metoda jest unikalna dla klasy. A default metoda jest unikalna dla instancji klasy.

Jeśli dodasz domyślną metodę do istniejącego interfejsu, klasy i interfejsy, które implementują ten interfejs, nie muszą go implementować. Mogą

  • zaimplementuj domyślną metodę, która nadpisuje implementację w zaimplementowanym interfejsie.
  • ponownie deklaruje metodę (bez implementacji), co czyni ją abstrakcyjną.
  • nic nie robić (wtedy domyślną metodą z zaimplementowanego interfejsu jest po prostu dziedziczne).

Więcej na ten temat tutaj .

 9
Author: kiriloff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-21 21:20:41

Remi Forax reguła to nie projektujesz z klasami abstrakcyjnymi. Projektujesz swoją aplikację za pomocą interfejsów . Watever jest wersją Javy, niezależnie od języka. Jest on wspierany przez Izasada segregacji nterface w Sol I D Zasady.

Możesz później użyć klas abstrakcyjnych do faktoryzacji kodu. Teraz z Java 8 można to zrobić bezpośrednio w interfejsie. To jest placówka, nie więcej.

 5
Author: Nicolas Zozol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-11 13:02:56

Kiedy powinien być używany interfejs z domyślnymi metodami, a kiedy abstrakt klasy być używane?

Zgodność wsteczna: Wyobraź sobie, że twój interfejs jest realizowany przez setki klas, modyfikując ten interfejs zmusi wszystkich użytkowników do wdrożenia nowo dodanej metody, nawet jeśli nie może to być istotne dla wielu innych klas, które implementują Twój interfejs, a także pozwala interfejs być funkcjonalne interfejs

Fakty I Ograniczenia:

1 - może być zadeklarowana tylko w interfejsie, a nie w klasie lub klasa abstrakcyjna.

2 - musi dostarczyć ciało

3-nie zakłada się, że jest abstrakcyjna, jak inne normalne metody używane w interfejsie.

 2
Author: Ahmad Sanie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-05 23:10:55

W Javie 8 interfejs wygląda jak abstrakcyjna klasa, chociaż mogą być pewne różnice, takie jak:

1) klasy abstrakcyjne są klasami, więc nie są ograniczone do innych ograniczeń interfejsu w Javie, np. klasa abstrakcyjna może mieć stan, ale nie możesz mieć stanu interfejsu w Javie.

2) kolejna semantyczna różnica między interfejsem z domyślnymi metodami a klasą abstrakcyjną jest taka, że można zdefiniować konstruktory wewnątrz abstrakcji klasy , ale nie można zdefiniować konstruktora wewnątrz interfejsu w Javie

 1
Author: Manish Sahni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-12 10:24:44

Domyślne metody w interfejsie Java powinny być częściej używane do dostarczania atrapy implementacji funkcji, dzięki czemu każda klasa implementacyjna tego interfejsu nie będzie musiała deklarować wszystkich abstrakcyjnych metod, nawet jeśli będą one miały do czynienia tylko z jedną. Domyślne metody w interfejsie są więc w pewien sposób bardziej zamiennikiem koncepcji klas adapterów.

Metody w klasie abstrakcyjnej powinny jednak dawać sensowną implementację, którą każda klasa potomna powinna nadpisać tylko w razie potrzeby zastąpić wspólną funkcjonalność.

 0
Author: shubh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-25 20:00:19

Jak wspomniano w innych odpowiedziach, możliwość dodania implementacji do interfejsu została dodana w celu zapewnienia wstecznej kompatybilności w ramach kolekcji. Argumentowałbym, że zapewnienie kompatybilności wstecznej jest potencjalnie jedynym dobrym powodem do dodania implementacji do interfejsu.

W Przeciwnym Razie, jeśli dodasz implementację do interfejsu, łamiesz fundamentalne prawo, dlaczego interfejsy zostały dodane w pierwszej kolejności. Java jest pojedynczym dziedziczeniem język, w przeciwieństwie do C++, który pozwala na wielokrotne dziedziczenie. Interfejsy zapewniają korzyści związane z pisaniem w języku, który obsługuje dziedziczenie wielokrotne, bez wprowadzania problemów związanych z dziedziczeniem wielokrotnym.

Dokładniej mówiąc, Java zezwala tylko na pojedyncze dziedziczenie implementacji, ale pozwala na wielokrotne dziedziczenie interfejsów. Na przykład, poniższy kod jest poprawny:

class MyObject extends String implements Runnable, Comparable { ... }

MyObject dziedziczy tylko jedną implementację, ale dziedziczy trzy Kontrakty.

Java przeszła wiele dziedziczeń implementacji, ponieważ wiele dziedziczeń implementacji wiąże się z wieloma problemami, które wykraczają poza zakres tej odpowiedzi. Interfejsy zostały dodane, aby umożliwić wielokrotne dziedziczenie kontraktów (interfejsy aka) bez problemów z wielokrotnym dziedziczeniem implementacji.

Aby poprzeć mój punkt widzenia, oto cytat Kena Arnolda i Jamesa Goslinga z książki the Java Programming Language, 4th wydanie :

Pojedyncze dziedziczenie wyklucza pewne użyteczne i poprawne wzory. Na problemy dziedziczenia wielokrotnego wynikają z dziedziczenia wielokrotnego implementacji, ale w wielu przypadkach dziedziczenie wielokrotne jest wykorzystywane do dziedziczyć szereg abstrakcyjnych umów i być może jeden konkretny wdrożenie. Zapewnienie sposobu dziedziczenia umowy abstrakcyjnej bez dziedziczenia implementacji pozwala na pisanie korzyści z dziedziczenie wielokrotne bez problemów z wielokrotnym realizacja spadek. Dziedziczenie umowy abstrakcyjnej określa się dziedziczenie interfejsu . Język programowania Java obsługuje dziedziczenie interfejsu, umożliwiając deklarowanie typu interface

 0
Author: johnnyodonnell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-30 05:24:19

Proszę najpierw pomyśleć o zasadzie open / closed. Domyślne metody w interfejsach go naruszają. Jest to zła funkcja w Javie. Zachęca do złego projektowania, złej architektury, niskiej jakości oprogramowania. Sugerowałbym całkowite unikanie używania domyślnych metod.

Zadaj sobie kilka pytań: Dlaczego nie można umieścić swoje metody do klasy abstrakcyjnej? Czy potrzebujesz więcej niż jednej klasy abstrakcyjnej? Zastanów się, za co odpowiada twoja klasa. Czy jesteś pewien, że wszystkie metody, które zamierzasz put to the single class naprawdę spełniają ten sam cel? Być może będziesz rozróżniać kilka celów, a następnie podzielisz swoją klasę na kilka klas, dla każdego celu swoją własną klasę.

 -1
Author: mentallurg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-08 06:26:27