Właśnie znalazłem statyczny interfejs zagnieżdżony w naszej bazie kodu.
class Foo {
public static interface Bar {
/* snip */
}
/* snip */
}
Nigdy wcześniej tego nie widziałem. Pierwotny programista jest poza zasięgiem. Dlatego muszę zapytać SO:
Jakie są semantyki za statycznym interfejsem? Co by się zmieniło, jeśli usunę static
? Dlaczego ktoś miałby to robić?
Odpowiedzi:
Słowo kluczowe static w powyższym przykładzie jest redundantne (interfejs zagnieżdżony jest automatycznie „statyczny”) i można je usunąć bez wpływu na semantykę; Polecam go usunąć. To samo dotyczy „publicznych” metod interfejsu i „publicznego finału” w polach interfejsu - modyfikatory są redundantne i po prostu dodają bałaganu do kodu źródłowego.
Tak czy inaczej, programista po prostu deklaruje interfejs o nazwie Foo.Bar. Nie ma dalszego powiązania z klasą obejmującą, z wyjątkiem tego, że kod, który nie może uzyskać dostępu do Foo, nie będzie mógł uzyskać dostępu do Foo.Bar. (Z kodu źródłowego - kod bajtowy lub odbicie może uzyskać dostęp do Foo.Bar, nawet jeśli Foo jest prywatny dla pakietu!)
Akceptowalnym stylem jest tworzenie zagnieżdżonego interfejsu w ten sposób, jeśli spodziewasz się, że będzie używany tylko z klasy zewnętrznej, aby nie tworzyć nowej nazwy najwyższego poziomu. Na przykład:
źródło
Odpowiedzi na pytanie, ale dobrym powodem do korzystania z zagnieżdżonego interfejsu jest to, że jego funkcja jest bezpośrednio związana z klasą, w której się znajduje. Dobrym tego przykładem jest
Listener
. Jeśli miałeś klasęFoo
i chciałeś, aby inne klasy mogły nasłuchiwać zdarzeń na niej, możesz zadeklarować interfejs o nazwieFooListener
, co jest w porządku, ale prawdopodobnie łatwiej byłoby zadeklarować interfejs zagnieżdżony i zaimplementować inne klasyFoo.Listener
( klasa zagnieżdżonaFoo.Event
nie jest zła).źródło
java.util.Map.Entry
(który jest interfejsem zagnieżdżonym w innym interfejsie).Map.Entry
) Lub klasy również w tym pakiecie. Mówię to, ponieważ lubię, aby moje lekcje były krótkie i rzeczowe. Również czytelnik może zobaczyć, jakie inne byty są powiązane z klasą, patrząc na klasy w pakiecie. Prawdopodobnie miałbym pakietjava.collections.map
map. Chodzi o OO i modułowość.java.util
ma w tym za dużo.util
jest jakcommon
- zapach IMOjava.util
pewno ma w tym za dużo. To powiedziawszy, nie sądzę, aby podział na tak drobnoziarniste pakiety, jak sugerujesz, byłby idealny.java.util.MapEntry
poza jego własnym pakietem. Pierwszy refleks: jakie są interfejsy związane z tą klasą? Patrzę na klasę. O ile javadoc nie prowadzi do tego interfejsu, nie mam pojęcia o ich związku. Plus ludzie nie patrzą na pakiet importu. Każdy ma swoje opinie. Nikt nie ma racji, nikt się nie myliInterfejsy członków są domyślnie statyczne. Modyfikator statyczny w twoim przykładzie można usunąć bez zmiany semantyki kodu. Zobacz także specyfikację języka Java 8.5.1. Statyczne deklaracje typu pręta
źródło
Wewnętrzny interfejs musi być statyczny, aby można było uzyskać do niego dostęp. Interfejs nie jest powiązany z instancjami klasy, ale z samą klasą, więc można uzyskać do niej dostęp w następujący
Foo.Bar
sposób:W większości przypadków nie różni się to od statycznej klasy wewnętrznej.
źródło
The interface isn't associated with instances of the class, but with the class itself
dalej, nie rozumiemOdpowiedź Jessego jest bliska, ale myślę, że istnieje lepszy kod, który pokazuje, dlaczego wewnętrzny interfejs może być przydatny. Zanim zaczniesz czytać, spójrz na poniższy kod. Czy możesz dowiedzieć się, dlaczego wewnętrzny interfejs jest użyteczny? Odpowiedź jest taka, że klasa DoSomethingAlready może być utworzona za pomocą dowolnej klasy, która implementuje A i C; nie tylko zoo konkretnej klasy. Oczywiście można to osiągnąć, nawet jeśli AC nie jest wewnętrzny, ale wyobraź sobie łączenie dłuższych nazw (nie tylko A i C) i robienie tego dla innych kombinacji (powiedzmy, A i B, C i B itp.) I łatwo zobaczyć, jak sprawy wymykają się spod kontroli. Nie wspominając o tym, że osoby przeglądające twoje drzewo źródłowe zostaną przytłoczone interfejsami, które mają znaczenie tylko w jednej klasie. Podsumowując,wewnętrzny interfejs umożliwia konstruowanie niestandardowych typów i poprawia ich enkapsulację .
źródło
Zoo
jest nie realizować interfejsAC
zatem przypadkiZoo
nie mogą być przekazywane do konstruktoraDoSomethingAlready
których oczekujeAC
. Fakt, któryAC
rozszerza oba,A
iC
nie oznacza, że klasy implementująA
iC
magicznie także implementująAC
.Aby odpowiedzieć na twoje pytanie bardzo bezpośrednio, spójrz na Map.Entry.
Map.Entry
może to również być przydatne
Wpis blogu statycznego zagnieżdżonego Inerfaces
źródło
Zazwyczaj widzę statyczne klasy wewnętrzne. Statyczne klasy wewnętrzne nie mogą odwoływać się do klas zawierających, o ile mogą to robić klasy niestatyczne. Chyba, że napotykasz jakieś kolizje pakietów (w tym samym pakiecie co Foo jest już interfejs o nazwie Bar). Myślę, że uczynię go własnym plikiem. Może to być również decyzja projektowa w celu wymuszenia logicznego połączenia między Foo a Barem. Być może autor chciał, aby Bar był używany tylko z Foo (chociaż statyczny interfejs wewnętrzny nie wymusza tego, tylko logiczne połączenie)
źródło
Jeśli zmienisz klasę Foo w interfejs Foo, słowo kluczowe „public” w powyższym przykładzie również będzie zbędne, ponieważ
źródło
W 1998 r. Philip Wadler zasugerował różnicę między interfejsami statycznymi a interfejsami niestatycznymi.
Na przykład zaproponował rozwiązanie problemu wyrażenia , które polega na niedopasowaniu wyrażenia jako „ile twój język może wyrazić” z jednej strony, a wyrażeniem jako „warunki, które próbujesz przedstawić w swoim języku” z drugiej strony .
Przykład różnicy między statycznymi i niestatycznymi zagnieżdżonymi interfejsami można zobaczyć w jego przykładowym kodzie :
Jego sugestia nigdy nie dotarła do Java 1.5.0. Dlatego wszystkie pozostałe odpowiedzi są poprawne: nie ma różnicy między statycznymi i niestatycznymi zagnieżdżonymi interfejsami.
źródło
W Javie interfejs / klasa statyczna umożliwia używanie interfejsu / klasy jak klasy najwyższego poziomu, tzn. Może być zadeklarowane przez inne klasy. Możesz więc:
Bez statycznego powyższego nie udałoby się skompilować. Zaletą tego jest to, że nie potrzebujesz nowego pliku źródłowego, aby zadeklarować interfejs. Również wizualnie kojarzy interfejs Bar z klasą Foo, ponieważ musisz napisać Foo.Bar i implikuje, że klasa Foo robi coś z instancjami Foo.Bar.
Opis typów klas w Javie .
źródło
Statyczny oznacza, że dowolna część klasy pakietu (projektu) może uzyskać do niego dostęp bez użycia wskaźnika. Może to być przydatne lub utrudniające w zależności od sytuacji.
Doskonałym przykładem przydatności metod „statycznych” jest klasa Math. Wszystkie metody matematyczne są statyczne. Oznacza to, że nie musisz zejść z drogi, stworzyć nowej instancji, zadeklarować zmienne i zapisać je w jeszcze większej liczbie zmiennych, możesz po prostu wprowadzić swoje dane i uzyskać wynik.
Statyczne nie zawsze jest tak przydatne. Jeśli na przykład porównujesz wielkość liter, możesz chcieć przechowywać dane na kilka różnych sposobów. Nie można utworzyć trzech metod statycznych z identycznymi podpisami. Potrzebujesz 3 różnych instancji, niestatycznych, a następnie możesz i porównaj, ponieważ jeśli jest statyczny, dane nie zmienią się wraz z danymi wejściowymi.
Metody statyczne są dobre dla jednorazowych zwrotów i szybkich obliczeń lub łatwych do uzyskania danych.
źródło