EDYCJA: Od Java 8 metody statyczne są teraz dozwolone w interfejsach.
Oto przykład:
public interface IXMLizable<T>
{
static T newInstanceFromXML(Element e);
Element toXMLElement();
}
Oczywiście, że to nie zadziała. Ale dlaczego nie?
Jednym z możliwych problemów może być to, co dzieje się, gdy zadzwonisz:
IXMLizable.newInstanceFromXML(e);
W tym przypadku myślę, że powinien wywołać pustą metodę (tj. {}). Wszystkie podklasy byłyby zmuszone do wdrożenia metody statycznej, więc wszystkie byłyby w porządku podczas wywoływania metody statycznej. Dlaczego to nie jest możliwe?
EDYCJA: Wydaje mi się, że szukam odpowiedzi głębszej niż „ponieważ taka jest Java”.
Czy istnieje szczególny technologiczny powód, dla którego metody statyczne nie mogą zostać zastąpione? To znaczy, dlaczego projektanci Java postanowili nadpisać metody instancji, ale nie metody statyczne?
EDYCJA: Problem z moim projektem polega na tym, że próbuję użyć interfejsów w celu wymuszenia konwencji kodowania.
Oznacza to, że cel interfejsu jest dwojaki:
Chcę, aby interfejs IXMLizable umożliwiał mi konwersję klas, które implementują go na elementy XML (przy użyciu polimorfizmu działa dobrze).
Jeśli ktoś chce stworzyć nową instancję klasy, która implementuje interfejs IXMLizable, zawsze będzie wiedział, że będzie nowy konstruktor statycznyInstanceFromXML (Element e).
Czy jest jakiś inny sposób, aby to zapewnić, poza umieszczeniem komentarza w interfejsie?
źródło
Odpowiedzi:
Java 8 zezwala na metody interfejsu statycznego
W Javie 8 interfejsy mogą mieć metody statyczne. Mogą także mieć konkretne metody instancji, ale nie pola instancji.
Są tutaj naprawdę dwa pytania:
Metody statyczne w interfejsach
Nie było silnego technicznego powodu, dla którego interfejsy nie mogły mieć metod statycznych w poprzednich wersjach. Ładnie to podsumowuje plakat z duplikatem pytania. Metody interfejsu statycznego były początkowo uważane za małą zmianę języka, a następnie pojawiła się oficjalna propozycja dodania ich w Javie 7, ale później porzucona z powodu nieprzewidzianych komplikacji.
Wreszcie, Java 8 wprowadziła metody interfejsu statycznego, a także metody instancji z możliwością zastąpienia z domyślną implementacją. Nadal nie mogą mieć pól instancji. Te funkcje są częścią obsługi wyrażeń lambda i możesz przeczytać o nich więcej w części H JSR 335.
Przesłanianie metod statycznych
Odpowiedź na drugie pytanie jest nieco bardziej skomplikowana.
Metody statyczne można rozwiązać w czasie kompilacji. Dynamiczne wysyłanie ma sens na przykład w przypadku metod, w których kompilator nie może określić konkretnego typu obiektu, a zatem nie może rozwiązać metody, która ma zostać wywołana. Jednak wywołanie metody statycznej wymaga klasy, a ponieważ klasa ta jest znana statycznie - w czasie kompilacji - dynamiczne wysyłanie nie jest konieczne.
Aby zrozumieć, co się tutaj dzieje, potrzebne jest trochę tła na temat działania metod instancji. Jestem pewien, że rzeczywista implementacja jest zupełnie inna, ale pozwól mi wyjaśnić moje pojęcie wysyłki metody, które modele dokładnie obserwowały zachowanie.
Udawaj, że każda klasa ma tablicę skrótów, która odwzorowuje sygnatury metod (nazwy i typy parametrów) na rzeczywistą część kodu, aby zaimplementować metodę. Gdy maszyna wirtualna próbuje wywołać metodę w instancji, sprawdza obiekt w swojej klasie i wyszukuje żądany podpis w tabeli klasy. Jeśli zostanie znalezione ciało metody, zostanie ono wywołane. W przeciwnym razie uzyskuje się klasę nadrzędną klasy i tam wyszukiwanie jest powtarzane. Dzieje się tak, dopóki nie zostanie znaleziona metoda lub nie będzie już klas nadrzędnych - w wyniku czego powstanie
NoSuchMethodError
.Jeśli zarówno nadklasa, jak i podklasa mają w swoich tabelach wpis dotyczący tej samej sygnatury metody, najpierw pojawia się wersja podklasy, a wersja nadklasy nigdy nie jest używana - jest to „przesłonięcie”.
Załóżmy teraz, że pomijamy instancję obiektu i zaczynamy od podklasy. Rozdzielczość może przebiegać jak wyżej, dając ci rodzaj „nadpisywalnej” metody statycznej. Rozdzielczość może się jednak zdarzyć w czasie kompilacji, ponieważ kompilator zaczyna od znanej klasy, zamiast czekać na środowisko wykonawcze w celu zapytania do obiektu o nieokreślonym typie dla swojej klasy. Nie ma sensu „zastępować” metody statycznej, ponieważ zawsze można określić klasę, która zawiera żądaną wersję.
„Interfejsy” konstruktora
Oto trochę więcej materiałów na temat ostatniej edycji pytania.
Wygląda na to, że chcesz skutecznie zlecić metodę podobną do konstruktora dla każdej implementacji
IXMLizable
. Zapomnij na chwilę o wymuszeniu tego za pomocą interfejsu i udawaj, że masz klasy, które spełniają to wymaganie. Jak byś tego użył?Ponieważ musisz wyraźnie nazwać konkretny typ
Foo
podczas „konstruowania” nowego obiektu, kompilator może sprawdzić, czy rzeczywiście ma on niezbędną metodę fabryczną. A jeśli nie, to co z tego? Jeśli mogę zaimplementować taki,IXMLizable
który nie ma „konstruktora”, i utworzę instancję i przekażę ją do twojego kodu, będzie on miałIXMLizable
niezbędny interfejs.Budowa jest częścią implementacji, a nie interfejsu. Każdy kod, który działa poprawnie z interfejsem, nie dba o konstruktora. Każdy kod, który dba o konstruktor, musi znać konkretny typ, a interfejs można zignorować.
źródło
RESET()
na danej klasie? Można by napisaćSomeClass.RESET()
. Więc nie potrzebujesz interfejsu do opisania tego API; jest statyczny. Interfejsy są używane, gdy nie znasz konkretnego typu w czasie kompilacji. Tak nigdy nie jest w przypadku metody statycznej.T
bez wiedzyT
statycznej, ponieważ obiecuję w interfejsie, że określony konstruktor (lub metoda statyczna) będzie istniał w czasie wykonywania. Fakt, że generowanie jest niemożliwe do określenia w Javie, nie oznacza, że nie jest to sensowne.To pytanie zostało już zadane i udzielono odpowiedzi tutaj
Aby powielić moją odpowiedź:
Nigdy nie ma sensu deklarować metody statycznej w interfejsie. Nie można ich wykonać za pomocą zwykłego wywołania MyInterface.staticMethod (). Jeśli wywołasz je, podając klasę implementacyjną MyImplementor.staticMethod (), musisz znać rzeczywistą klasę, więc nie ma znaczenia, czy interfejs ją zawiera, czy nie.
Co ważniejsze, metody statyczne nigdy nie są zastępowane, a jeśli spróbujesz:
reguły statyczne mówią, że należy wykonać metodę zdefiniowaną w zadeklarowanym typie zmiennej. Ponieważ jest to interfejs, jest to niemożliwe.
Powodem, dla którego nie można wykonać polecenia „result = MyInterface.staticMethod ()” jest to, że musiałby wykonać wersję metody zdefiniowanej w MyInterface. Ale nie można zdefiniować wersji w MyInterface, ponieważ jest to interfejs. Z definicji nie ma kodu.
Chociaż można powiedzieć, że sprowadza się to do „ponieważ Java robi to w ten sposób”, w rzeczywistości decyzja jest logiczną konsekwencją innych decyzji projektowych, również podjętych z bardzo ważnego powodu.
źródło
static
jest kiepskim terminem w językach i został rozciągnięty zbyt daleko. Samo to jest już szkicowe. Zobacz mój przykład powyżej stackoverflow.com/questions/512877/... {wzruszenie ramion}.Zwykle odbywa się to za pomocą wzoru fabrycznego
źródło
Wraz z pojawieniem się Java 8 możliwe jest teraz pisanie domyślnych i statycznych metod w interfejsie. docs.oracle/staticMethod
Na przykład:
Wynik : 6
WSKAZÓWKA: Wywołanie metody interfejsu statycznego nie wymaga implementacji przez żadną klasę. Z pewnością dzieje się tak, ponieważ te same reguły dla metod statycznych w superklasach mają zastosowanie do metod statycznych na interfejsach.
źródło
Ponieważ metod statycznych nie można zastąpić w podklasach, a zatem nie mogą być abstrakcyjne. Wszystkie metody interfejsu są de facto abstrakcyjne.
źródło
Właściwie możesz w Javie 8.
Zgodnie z dokumentacją Java :
W Javie 8 interfejs może mieć metody domyślne i metody statyczne . Ułatwia nam to organizowanie metod pomocniczych w naszych bibliotekach. Możemy zachować metody statyczne specyficzne dla interfejsu w tym samym interfejsie, a nie w osobnej klasie.
Przykład domyślnej metody:
zamiast
Przykład metody statycznej (z samego dokumentu ):
źródło
Interfejsy dotyczą polimorfizmu, który jest nieodłącznie związany z instancjami obiektów, a nie klasami. Dlatego statyczny nie ma sensu w kontekście interfejsu.
źródło
Po pierwsze, wszystkie decyzje językowe są decyzjami podejmowanymi przez twórców języków. W świecie inżynierii oprogramowania, definiowania języka lub pisania kompilatora / interpretera nie ma nic, co mówi, że metoda statyczna nie może być częścią interfejsu. Stworzyłem dla nich kilka języków i napisałem dla nich kompilatory - wszystko to po prostu siedzi i określa znaczącą semantykę. Twierdziłbym, że semantyka metody statycznej w interfejsie jest wyjątkowo jasna - nawet jeśli kompilator musi odroczyć rozdzielczość metody w czasie wykonywania.
Po drugie, że w ogóle używamy metod statycznych, oznacza to, że istnieje prawidłowy powód posiadania wzorca interfejsu, który obejmuje metody statyczne - nie mogę mówić za żadnego z was, ale regularnie używam metod statycznych.
Najbardziej prawdopodobną prawidłową odpowiedzią jest to, że w czasie definiowania języka nie było zauważalnej potrzeby stosowania metod statycznych w interfejsach. Java znacznie się rozwinęła przez lata i jest to przedmiot, który najwyraźniej zyskał zainteresowanie. To, że zostało sprawdzone dla Javy 7, wskazuje, że wzrósł on do poziomu zainteresowania, który może spowodować zmianę języka. Ja, na przykład, będę szczęśliwy, gdy nie będę już musiał tworzyć instancji obiektu, aby móc wywołać moją metodę niestatystyczną gettera, aby uzyskać dostęp do zmiennej statycznej w instancji podklasy ...
źródło
Metody statyczne nie są wirtualne jak metody instancji, więc przypuszczam, że projektanci Java zdecydowali, że nie chcą ich w interfejsach.
Ale możesz umieścić klasy zawierające metody statyczne w interfejsach. Możesz tego spróbować!
źródło
Pozwólcie, że przeredaguję to pytanie, wypełniając definicje.
Lub, mówiąc dokładniej, jeśli chcę wywołać metodę bez instancji, ale znając klasę, jak mogę ją rozwiązać na podstawie instancji, której nie mam.
źródło
W kilku odpowiedziach omówiono problemy z koncepcją nadpisywalnych metod statycznych. Czasami jednak natrafiasz na wzór, w którym wydaje się, że właśnie tego chcesz użyć.
Na przykład pracuję z warstwą obiektowo-relacyjną, która ma obiekty wartości, ale także polecenia do manipulowania obiektami wartości. Z różnych powodów każda klasa obiektu wartości musi zdefiniować niektóre metody statyczne, które pozwalają ramce znaleźć instancję polecenia. Na przykład, aby utworzyć osobę, którą zrobiłbyś:
i aby załadować osobę według identyfikatora, który zrobisz
Jest to dość wygodne, jednak ma swoje problemy; zwłaszcza interfejs nie może wymuszać istnienia metod statycznych. Nadrzędna metoda statyczna w interfejsie byłaby dokładnie tym, czego potrzebowalibyśmy, gdyby tylko jakoś działała.
EJB rozwiązują ten problem, mając interfejs domowy; każdy obiekt wie, jak znaleźć swój Dom, a Dom zawiera metody „statyczne”. W ten sposób metody „statyczne” można w razie potrzeby zastąpić i nie zaśmiecać normalnego interfejsu (nazywa się to „zdalnym”) metodami, które nie dotyczą instancji komponentu bean. Wystarczy, że normalny interfejs określi metodę „getHome ()”. Zwraca instancję obiektu Home (który, jak sądzę, może być singletonem), a osoba dzwoniąca może wykonywać operacje, które wpływają na wszystkie obiekty Person.
źródło
Komentowanie
EDIT: As of Java 8, static methods are now allowed in interfaces.
To prawda, statyczne metody, ponieważ Java 8 są dozwolone w interfejsach, ale twój przykład nadal nie działa. Nie możesz po prostu zdefiniować metody statycznej: musisz ją zaimplementować lub otrzymasz błąd kompilacji.
źródło
Cóż, bez ogólnych, statyczne interfejsy są bezużyteczne, ponieważ wszystkie statyczne wywołania metod są rozstrzygane w czasie kompilacji. Więc nie ma dla nich prawdziwego zastosowania.
W przypadku generycznych mają zastosowanie - z domyślną implementacją lub bez niej. Oczywiście musiałoby to być nadrzędne i tak dalej. Jednak przypuszczam, że takie użycie nie było bardzo OO (jak wskazują inne odpowiedzi tępo), a zatem nie było uważane za warte wysiłku, który wymagałoby wdrożenia.
źródło
Wszystkie metody w interfejsie są jawnie abstrakcyjne, dlatego nie można ich zdefiniować jako statycznych, ponieważ metody statyczne nie mogą być abstrakcyjne.
źródło
Interfejsu nigdy nie można wyrejestrować statycznie, np
ISomething.member
. Interfejs jest zawsze wyłuskiwany przez zmienną, która odnosi się do instancji podklasy interfejsu. Zatem odwołanie interfejsu nigdy nie może wiedzieć, do której podklasy się odwołuje, bez wystąpienia jego podklasy.Zatem najbliższym przybliżeniem do metody statycznej w interfejsie byłaby metoda niestatyczna, która ignoruje „to”, tj. Nie uzyskuje dostępu do żadnych niestatycznych elementów instancji. W przypadku abstrakcji niskiego poziomu każda metoda niestatyczna (po wyszukaniu w dowolnej tabeli vt) jest tak naprawdę tylko funkcją o zakresie klasy, która przyjmuje „to” jako domyślny parametr formalny. Zobacz pojedynczy obiekt Scali i interoperacyjność z Javą jako dowód tej koncepcji. Dlatego każda metoda statyczna jest funkcją o zasięgu klasy, która nie przyjmuje parametru „this”. W ten sposób zwykle można wywoływać metodę statyczną, ale jak wcześniej wspomniano, interfejs nie ma implementacji (jest abstrakcyjny).
Zatem, aby uzyskać najbliższe przybliżenie do metody statycznej w interfejsie, należy zastosować metodę niestatyczną, a następnie nie uzyskiwać dostępu do żadnego z elementów niestatycznej instancji. Nie byłoby żadnej możliwej korzyści z wydajności w żaden inny sposób, ponieważ nie ma możliwości statycznego połączenia (w czasie kompilacji) a
ISomething.member()
. Jedyną korzyścią, jaką widzę w przypadku metody statycznej w interfejsie, jest to, że nie wprowadzałaby (tzn. Ignorowała) niejawne „to”, a tym samym uniemożliwiała dostęp do któregokolwiek z elementów instancji niestatycznej. Oznaczałoby to domyślnie, że funkcja, która nie ma dostępu do „tego”, jest niezmienna, a nawet nie tylko w odniesieniu do jej zawierającej klasy. Ale deklaracja „statyczna” w interfejsieISomething
dezorientowałaby także ludzi, którzy próbowali uzyskać do niej dostępISomething.member()
co spowodowałoby błąd kompilatora. Podejrzewam, że jeśli błąd kompilatora byłby wystarczająco wyjaśniający, byłoby lepiej niż próbować edukować ludzi na temat korzystania z metody niestatycznej, aby osiągnąć to, czego chcą (najwyraźniej głównie metody fabryczne), tak jak my to robimy (i powtarzano to przez 3 Pytania i odpowiedzi na tej stronie), więc jest to oczywiście problem, który nie jest intuicyjny dla wielu osób. Musiałem się nad tym zastanowić, aby uzyskać właściwe zrozumienie.Aby uzyskać zmienne pole statyczne w interfejsie, należy użyć niestatystycznych metod pobierających i ustawiających w interfejsie, aby uzyskać dostęp do tego pola statycznego w podklasie. Sidenote, pozornie niezmienna statystyka może być zadeklarowana w interfejsie Java za pomocą
static final
.źródło
Interfejsy po prostu dostarczają listę rzeczy, które zapewni klasa, a nie rzeczywistą implementację tych rzeczy, co jest twoim statycznym przedmiotem.
Jeśli chcesz statyki, użyj klasy abstrakcyjnej i odziedzicz ją, w przeciwnym razie usuń statyczną.
Mam nadzieję, że to pomaga!
źródło
Nie można zdefiniować metod statycznych w interfejsie, ponieważ metody statyczne należą do klasy, a nie do instancji klasy, a interfejsy nie są klasami. Przeczytaj więcej tutaj.
Jeśli jednak chcesz, możesz to zrobić:
W tym przypadku masz dwie klasy z 2 odrębnymi metodami statycznymi o nazwie methodX ().
źródło
Załóżmy, że możesz to zrobić; rozważ ten przykład:
źródło
A.thisIsTheMethod()
, wydrukuje „Jestem klasy B”.B.thisIsTheMethod()
, wydrukuje „Jestem klasy B”.Coś, co można zaimplementować, to interfejs statyczny (zamiast metody statycznej w interfejsie). Wszystkie klasy implementujące dany interfejs statyczny powinny implementować odpowiednie metody statyczne. Możesz uzyskać statyczny interfejs SI z dowolnego używanego klasy
wtedy możesz zadzwonić
si.method(params)
. Byłoby to przydatne (na przykład w przypadku fabrycznego wzorca projektowego), ponieważ można uzyskać (lub sprawdzić implementację) implementację metod statycznych SI z nieznanej klasy czasu kompilacji! Dynamiczna wysyłka jest konieczna i można przesłonić metody statyczne (jeśli nie ostateczne) klasy, rozszerzając je (wywoływane przez interfejs statyczny). Oczywiście metody te mają dostęp tylko do zmiennych statycznych swojej klasy.źródło
Chociaż zdaję sobie sprawę, że Java 8 rozwiązuje ten problem, pomyślałem, że wkroczę do scenariusza, nad którym obecnie pracuję (zablokowany przy użyciu Java 7), w którym pomocne byłoby określenie metod statycznych w interfejsie.
Mam kilka definicji wyliczenia, w których zdefiniowałem pola „id” i „displayName” wraz z metodami pomocniczymi oceniającymi wartości z różnych powodów. Implementacja interfejsu pozwala mi upewnić się, że metody gettera są na miejscu, ale nie metody statycznego pomocnika. Będąc wyliczeniem, naprawdę nie ma czystego sposobu na przeniesienie metod pomocniczych do odziedziczonej klasy abstrakcyjnej lub czegoś podobnego, więc metody muszą być zdefiniowane w samym wyliczeniu. Ponieważ jest to wyliczenie, nigdy nie byłbyś w stanie przekazać go jako obiektu instancji i traktować go jako typ interfejsu, ale lubię istnieć metody statycznego pomocnika przez interfejs, co lubię jest obsługiwany w Javie 8.
Oto kod ilustrujący mój punkt widzenia.
Definicja interfejsu:
Przykład jednej definicji wyliczenia:
Ogólna definicja narzędzia wyliczeniowego:
źródło
Załóżmy, że w interfejsach dozwolone są metody statyczne: * Zmusiłyby wszystkie klasy implementujące do zadeklarowania tej metody. * Interfejsy byłyby zwykle używane przez obiekty, więc jedynymi skutecznymi metodami byłyby metody niestatyczne. * Każda klasa, która zna określony interfejs, może wywoływać swoje metody statyczne. Stąd metoda statyczna klasy implementującej zostałaby wywołana poniżej, ale klasa wywołująca nie wie, która. Jak to wiedzieć? Zgadnij, że nie ma instancji!
Uważano, że interfejsy są używane podczas pracy z obiektami. W ten sposób obiekt jest tworzony z określonej klasy, więc ta ostatnia sprawa została rozwiązana. Klasa wywołująca nie musi wiedzieć, która konkretna klasa, ponieważ tworzenie instancji może być wykonane przez trzecią klasę. Klasa wywołująca zna tylko interfejs.
Jeśli chcemy, aby zostało to rozszerzone na metody statyczne, powinniśmy mieć możliwość wcześniejszego sprecyzowania klasy implementującej, a następnie przekazania odwołania do klasy wywołującej. Może to wykorzystać klasę za pomocą metod statycznych w interfejsie. Ale czym różni się to odniesienie od obiektu? Potrzebujemy tylko obiektu reprezentującego klasę. Teraz obiekt reprezentuje starą klasę i mógłby zaimplementować nowy interfejs, w tym stare metody statyczne - teraz są one niestatyczne.
Metaklasy służą do tego celu. Możesz wypróbować klasę Java. Problem polega jednak na tym, że Java nie jest na to wystarczająco elastyczna. Nie można zadeklarować metody w obiekcie klasy interfejsu.
To jest problem z meta - kiedy musisz zrobić tyłek
..bla bla
w każdym razie masz łatwe obejście - dzięki czemu metoda jest niestatyczna z tą samą logiką. Ale najpierw musisz utworzyć obiekt, aby wywołać metodę.
źródło
Aby rozwiązać ten problem: błąd: brak metody lub zadeklaruj streszczenie static void main (String [] args);
wyjście: 20
Teraz możemy użyć metody statycznej w interfejsie
źródło
Myślę, że java nie ma statycznych metod interfejsu, ponieważ nie są one potrzebne. Możesz myśleć, że tak, ale ... Jak byś ich użył? Jeśli chcesz do nich zadzwonić jak
to nie musisz deklarować tego w interfejsie. Jeśli chcesz do nich zadzwonić jak
to nie powinno być statyczne. Jeśli faktycznie zamierzasz użyć pierwszego sposobu, ale po prostu chcesz wymusić na każdej implementacji taką statyczną metodę, to tak naprawdę jest to konwencja kodowania, a nie umowa między instancją, która implementuje interfejs i kod wywołujący.
Interfejsy pozwalają zdefiniować kontrakt między instancją klasy, która implementuje interfejs i kod wywołujący. A java pomaga mieć pewność, że ta umowa nie zostanie naruszona, więc możesz na niej polegać i nie martw się, która klasa implementuje tę umowę, wystarczy „ktoś, kto podpisał umowę”. W przypadku interfejsów statycznych Twój kod
nie polega na tym, że każda implementacja interfejsu ma tę metodę, więc nie potrzebujesz java, aby być pewnym.
źródło
Jaka jest potrzeba metody statycznej w interfejsie, metody statyczne są używane w zasadzie, gdy nie trzeba tworzyć instancji obiektu, cała idea interfejsu polega na wprowadzeniu koncepcji OOP z wprowadzeniem metody statycznej, którą odwracasz od koncepcji.
źródło