Z mojego zrozumienia, jeśli implementujesz interfejs w java, metody określone w tym interfejsie muszą być używane przez podklasy implementujące wspomniany interfejs.
Zauważyłem, że w niektórych interfejsach, takich jak interfejs Collection, istnieją metody, które są komentowane jako opcjonalne, ale co to dokładnie oznacza? Trochę mnie to rzuciło, bo myślałem, że wszystkie metody określone w interfejsie będą wymagane?
Odpowiedzi:
Wydaje się, że w odpowiedziach jest strasznie dużo niejasności.
Język Java wymaga, aby każda metoda interfejsu była implementowana przez każdą implementację tego interfejsu. Kropka. Nie ma wyjątków od tej zasady. Powiedzenie „Kolekcje są wyjątkiem” sugeruje bardzo niejasne zrozumienie tego, co się tutaj naprawdę dzieje.
Ważne jest, aby zdać sobie sprawę, że istnieją dwa poziomy dostosowania się do interfejsu:
Co może sprawdzić język Java. To właściwie sprowadza się do: czy jest jakaś implementacja dla każdej z metod?
Faktycznie wywiązuje się z umowy. To znaczy, czy implementacja robi to, co dokumentacja interfejsu mówi, że powinna?
Dobrze napisane interfejsy będą zawierać dokumentację wyjaśniającą dokładnie, czego oczekuje się od implementacji. Twój kompilator nie może tego sprawdzić za Ciebie. Musisz przeczytać dokumenty i robić to, co mówią. Jeśli nie zrobisz tego, co mówi umowa, będziesz mieć implementację interfejsu, jeśli chodzi o kompilator , ale będzie to wadliwa / nieprawidłowa implementacja.
Projektując API Collections, Joshua Bloch zdecydował, że zamiast bardzo drobnoziarnistych interfejsów rozróżniać różne warianty kolekcji (np. Czytelne, zapisywalne, o swobodnym dostępie itp.), Będzie miał tylko bardzo zgrubny zestaw interfejsów, głównie
Collection
,List
,Set
iMap
, a następnie udokumentować niektórych operacji jako „opcjonalne”. Miało to na celu uniknięcie kombinatorycznej eksplozji, która wynikałaby z drobnoziarnistych interfejsów. Z często zadawanych pytań dotyczących projektowania interfejsu API kolekcji Java :Kiedy metody w API Collections są udokumentowane jako „operacje opcjonalne”, nie oznacza to, że możesz po prostu pozostawić implementację metody w implementacji, ani nie oznacza to, że możesz użyć pustej treści metody (po pierwsze, wiele z muszą zwrócić wynik). Oznacza to raczej, że prawidłowym wyborem implementacji (takim, który nadal jest zgodny z umową) jest wyrzucenie pliku
UnsupportedOperationException
.Zauważ, że ponieważ
UnsupportedOperationException
jest aRuntimeException
, możesz go wyrzucić z dowolnej implementacji metody, jeśli chodzi o kompilator. Na przykład możesz wyrzucić to z implementacjiCollection.size()
. Jednak taka realizacja naruszyłaby umowę, ponieważ dokumentacjaCollection.size()
nie mówi, że jest to dozwolone.Na marginesie: Podejście używane przez API Collections w Javie jest nieco kontrowersyjne (prawdopodobnie jednak mniej niż teraz, gdy zostało wprowadzone po raz pierwszy). W idealnym świecie interfejsy nie miałyby opcjonalnych operacji, a zamiast tego byłyby używane precyzyjne interfejsy. Problem polega na tym, że Java nie obsługuje ani wywnioskowanych typów strukturalnych, ani typów przecięcia, dlatego też próba robienia rzeczy we „właściwy sposób” kończy się w przypadku kolekcji wyjątkowo nieporęczną pracą.
źródło
There are no exceptions to this rule
. Zastanawiasz się, dlaczego ta odpowiedź nie jest oznaczona jako zaakceptowana. Inni są dobrzy, ale dałeś więcej niż wystarczająco.Foo
który nie jest implementowanyRunnable
metodą publicznąvoid run()
. Teraz utworzyć klasęBar
, żeextends Foo
iimplements Runnable
bez overidingrun
. Nadal implementuje metodę, choć pośrednio. Podobnie domyślna implementacja metody jest nadal implementacją.remove
podano domyślną implementację. Jeśli tego nie zaimplementujesz, Twoja klasa otrzyma domyślną implementację. Pozostałe dwie metody, o których wspomniałeś, nie mają domyślnych implementacji.Aby skompilować implementującą (nieabstrakcyjną) klasę dla interfejsu - należy zaimplementować wszystkie metody.
Jeśli jednak pomyślimy o metodzie, której implementacja jest prostym rzutem wyjątku, jako o `` niezaimplementowanej '' metodzie (jak niektóre metody w
Collection
interfejsie), toCollection
interfejs jest w tym przypadku wyjątkiem, a nie zwykłym przypadkiem. Zwykle klasa implementująca powinna (i będzie) implementowała wszystkie metody.„Opcjonalne” w kolekcji oznacza, że klasa implementująca nie musi jej „implementować” (zgodnie z powyższą terminologią) i po prostu ją wyrzuci
NotSupportedException
.Dobry przykład-
add()
metoda niezmiennych kolekcji - beton po prostu zaimplementuje metodę, która nie robi nic poza rzucaniemNotSupportedException
W takim przypadku
Collection
ma to na celu zapobieganie bałaganiarskim drzewom dziedziczenia, które spowodują, że programiści będą nieszczęśliwi - ale dla większości przypadków ten paradygmat nie jest zalecany i należy go unikać, jeśli to możliwe.Aktualizacja:
Od wersji java 8 metoda domyślna .
Oznacza to, że interfejs może definiować metodę - w tym jej implementację.
Zostało to dodane, aby umożliwić dodawanie funkcjonalności do interfejsów, jednocześnie wspierając kompatybilność wsteczną dla fragmentów kodu, które nie wymagają nowej funkcjonalności.
Zauważ, że metoda jest nadal implementowana przez wszystkie klasy, które ją deklarują, ale używają definicji interfejsu.
źródło
Interfejs w Javie po prostu deklaruje kontrakt na implementację klas. Wszystkie metody w tym interfejsie muszą zostać zaimplementowane, ale klasy implementujące mogą pozostawić je niezaimplementowane, a mianowicie puste. Jako wymyślony przykład,
Teraz pozostawiłem
doSomethingElse()
niezaimplementowany, pozostawiając go swobodnym do implementacji dla moich podklas. To jest opcjonalne.Jeśli jednak mówisz o interfejsach kolekcji, jak powiedzieli inni, są one wyjątkiem. Jeśli pewne metody pozostaną niezaimplementowane i wywołasz je, mogą generować
UnsupportedOperationException
wyjątki.źródło
Opcjonalne metody w interfejsie Collection oznaczają, że implementacja metody może zgłosić wyjątek, ale i tak musi zostać zaimplementowana. Jak określono w dokumentach :
źródło
new Runnable ( ) { @ Override public void run ( ) { throw new UnsupportedOperationException ( ) ; } }
:;add((T)null)
może być ważne w jednym przypadku, ale nie w innym. Oznacza to, że mówi o opcjonalnych wyjątkach / zachowaniu i argumentach ("ograniczenia dotyczące elementów" ... "niekwalifikowalny element" ... "wyjątki oznaczone jako opcjonalne") i nie dotyczy metod opcjonalnych .Aby kod mógł się skompilować, muszą zostać zaimplementowane wszystkie metody (poza tymi z
default
implementacjami w Javie 8+), ale implementacja nie musi robić nic użytecznego funkcjonalnie. W szczególności:UnsupportedOperationException
(lub podobny)To drugie podejście jest często stosowane w klasach kolekcji - wszystkie metody są nadal zaimplementowane, ale niektóre mogą zgłosić wyjątek, jeśli zostaną wywołane w czasie wykonywania.
źródło
W rzeczywistości inspiruje mnie SurfaceView.Callback2. Myślę, że to oficjalny sposób
Jeśli Twoja klasa nie musi implementować metod opcjonalnych, po prostu „implementuje wywołanie zwrotne”. Jeśli Twoja klasa wymaga implementacji metod opcjonalnych, po prostu „implementuje CallbackExtended”.
Przepraszam za gówno angielski.
źródło
W Javie 8 i późniejszych, odpowiedź na to pytanie jest nadal aktualna, ale teraz jest bardziej zniuansowana.
Po pierwsze, te stwierdzenia z zaakceptowanej odpowiedzi pozostają poprawne:
A więc jakie są nowe niuanse w Javie 8? Mówiąc o „metodach opcjonalnych”, można zastosować dowolne z poniższych:
1. Metoda, której wdrożenie jest umownie opcjonalne
„Trzecie stwierdzenie” mówi, że abstrakcyjne metody interfejsu muszą być zawsze implementowane i tak jest w Javie 8+. Jednak, podobnie jak w Java Collections Framework, niektóre abstrakcyjne metody interfejsu można opisać jako „opcjonalne” w kontrakcie.
W takim przypadku autor implementujący interfejs może zrezygnować z implementacji metody. Kompilator będzie jednak nalegał na implementację, więc autor używa tego kodu dla dowolnych metod opcjonalnych, które nie są potrzebne w danej klasie implementacji:
W Javie 7 i wcześniejszych była to tak naprawdę jedyna „metoda opcjonalna”, która istniała, tj. Metoda, która, jeśli nie została zaimplementowana, zgłosiła wyjątek UnsupportedOperationException. To zachowanie jest koniecznie określone w kontrakcie interfejsu (np. Opcjonalne metody interfejsu Java Collections Framework).
2. Metoda domyślna, której ponowna implementacja jest opcjonalna
Java 8 wprowadziła koncepcję metod domyślnych . Są to metody, których implementacja może być i jest zapewniana przez samą definicję interfejsu. Generalnie możliwe jest udostępnienie metod domyślnych tylko wtedy, gdy treść metody może być napisana przy użyciu innych metod interfejsu (tj. „Prymitywów”) i kiedy
this
może oznaczać „ten obiekt, którego klasa zaimplementowała ten interfejs”.Metoda domyślna musi spełniać kontrakt interfejsu (tak jak każda inna implementacja metody interfejsu). Dlatego określenie implementacji metody interfejsu w klasie implementującej jest w gestii autora (o ile zachowanie jest zgodne z jego przeznaczeniem).
W tym nowym środowisku Java Collections Framework można przepisać jako:
W ten sposób metoda „opcjonalna”
add()
ma domyślne zachowanie polegające na zgłaszaniu wyjątku UnsupportedOperationException, jeśli klasa implementująca nie zapewnia własnego nowego zachowania, co jest dokładnie tym, co chciałbyś, aby się wydarzyło i jest zgodne z umową dotyczącą List. Jeśli autor pisze klasę, która nie pozwala na dodawanie nowych elementów do implementacji List, implementacjaadd()
jest opcjonalna, ponieważ domyślne zachowanie jest dokładnie tym, co jest potrzebne.W tym przypadku „trzecia instrukcja” powyżej nadal jest prawdziwa, ponieważ metoda została zaimplementowana w samym interfejsie.
3. Metoda zwracająca
Optional
wynikOstatnim nowym rodzajem metody opcjonalnej jest po prostu metoda, która zwraca
Optional
. TaOptional
klasa zapewnia zdecydowanie bardziej zorientowany obiektowo sposób postępowanianull
wynikami.W płynnym stylu programowania, takim jak typowy typowy podczas kodowania za pomocą nowego interfejsu API strumieniowania w języku Java, wynik zerowy w dowolnym momencie powoduje awarię programu z wyjątkiem NullPointerException. Plik
Optional
Klasa zapewnia mechanizm zwracania wyników zerowych do kodu klienta w sposób, który umożliwia płynny styl bez powodowania kod klienta do katastrofy.źródło
Jeśli przejdziemy przez kod AbstractCollection.java w grepCode, który jest klasą nadrzędną dla wszystkich implementacji kolekcji, pomoże nam to zrozumieć znaczenie metod opcjonalnych. Oto kod metody add (e) w klasie AbstractCollection. metoda add (e) jest opcjonalna zgodnie z interfejsem kolekcji
Metoda opcjonalna oznacza, że jest już zaimplementowana w klasach nadrzędnych i zgłasza UnsupportedOperationException przy wywołaniu. Jeśli chcemy, aby nasza kolekcja była modyfikowalna, powinniśmy przesłonić opcjonalne metody w interfejsie kolekcji.
źródło
Cóż, ten temat został skierowany do ... tak ... ale myślę, że brakuje jednej odpowiedzi. Mówię o „domyślnych metodach” interfejsów. Na przykład, wyobraźmy sobie, że masz klasę do zamykania czegokolwiek (np. Destruktora lub czegoś podobnego). Powiedzmy, że powinno mieć 3 metody. Nazwijmy je „doFirst ()”, „doLast ()” i „onClose ()”.
Więc mówimy, że chcemy, aby każdy obiekt tego typu przynajmniej realizował "onClose ()", ale pozostałe są opcjonalne.
Możesz to sobie uświadomić, używając "domyślnych metod" interfejsów. Wiem, że przez większość czasu zanegowałoby to przyczynę interfejsu, ale jeśli projektujesz framework, może to być przydatne.
Więc jeśli chcesz to zrealizować w ten sposób, wyglądałoby to następująco
Co by się teraz stało, gdybyś na przykład zaimplementował go w klasie o nazwie „Test”, kompilator byłby w porządku z następującymi elementami:
z wyjściem:
lub
z wyjściem:
Możliwe są wszystkie kombinacje. Wszystko, co ma wartość „domyślną”, może zostać zaimplementowane, ale nie może, jednak wszystko bez musi zostać wdrożone.
Mam nadzieję, że nie jest całkowicie błędne, że teraz odpowiadam.
Życzę wszystkim miłego dnia!
[edit1]: Uwaga: to działa tylko w Javie 8.
źródło
Szukałem sposobu na zaimplementowanie interfejsu wywołania zwrotnego, więc zaimplementowanie metod opcjonalnych było konieczne, ponieważ nie chciałem implementować każdej metody dla każdego połączenia zwrotnego.
Zamiast więc korzystać z interfejsu, użyłem klasy z pustą implementacją, taką jak:
I możesz ustawić zmienną członkowską CallBack w ten sposób:
to nazwij to tak.
W ten sposób nie musisz martwić się o implementację wszystkich metod na wywołanie zwrotne, a jedynie nadpisać te, których potrzebujesz.
źródło
Chociaż nie odpowiada to na pytanie OP, warto zauważyć, że od wersji Java 8 dodawanie domyślnych metod do interfejsów jest w rzeczywistości możliwe . Słowo
default
kluczowe umieszczone w sygnaturze metody interfejsu spowoduje, że klasa będzie miała opcję nadpisania metody, ale nie będzie tego wymagać.źródło
Samouczek dotyczący kolekcji Java firmy Oracle:
źródło