Przeczytałem to pytanie i pomyślałem, że łatwo byłoby rozwiązać (nie bez tego, że nie da się go rozwiązać), gdyby można napisać:
@Override
public String toString() {
return super.super.toString();
}
Nie jestem pewien, czy jest przydatny w wielu przypadkach, ale zastanawiam się, dlaczego tak nie jest i czy coś takiego istnieje w innych językach.
Co myślicie?
EDYCJA: Aby wyjaśnić: tak, wiem, w Javie jest to niemożliwe i tak naprawdę nie tęsknię. Nie spodziewałem się, że zadziała i byłem zaskoczony otrzymaniem błędu kompilatora. Właśnie wpadłem na pomysł i lubię o tym dyskutować.
java
superclass
Tim Büthe
źródło
źródło
super.super.toString()
sprzeczna z twoją własną decyzją, kiedy zdecydujesz się rozszerzyć klasę, akceptując w ten sposób wszystkie (a nie niektóre) jej cechy.Odpowiedzi:
Narusza to kapsułkowanie. Nie powinieneś być w stanie ominąć zachowania klasy nadrzędnej. Czasami warto ominąć zachowanie własnej klasy (szczególnie z tej samej metody), ale nie zachowanie rodzica. Załóżmy na przykład, że mamy podstawową „kolekcję przedmiotów”, podklasę reprezentującą „kolekcję czerwonych przedmiotów” i podklasę tej reprezentującą „kolekcję dużych czerwonych przedmiotów”. Sensowne jest posiadanie:
W porządku - RedItems zawsze może być pewien, że wszystkie zawarte w nim przedmioty są czerwone. Teraz załóżmy, że byli w stanie wywołać super.super.add ():
Teraz możemy dodać, co chcemy, a niezmiennik w
RedItems
jest zepsuty.Czy to ma sens?
źródło
Myślę, że Jon Skeet ma poprawną odpowiedź. Chciałbym tylko dodać, że można uzyskać dostęp do zmiennych zaciemnionych z nadklas superklas, przesyłając
this
:co daje wynik:
(przykład z JLS )
Nie działa to jednak w przypadku wywołań metod, ponieważ wywołania metod są określane na podstawie typu środowiska wykonawczego obiektu.
źródło
Myślę, że następujący kod pozwala na użycie super.super ... super.method () w większości przypadków. (nawet jeśli jest to brzydkie)
W skrócie
Stosowanie :
źródło
super.super.
zachęca programistów do znalezienia nowych, zawiłych i skandalicznych sposobów strzelania sobie w stopę w celu obejścia tego problemu, jest to doskonały przykład tego, ponieważ koledzy prawdopodobnie będą cię tak bardzo nienawidzić za napisanie czegoś tak, że osobiście i dosłownie zastrzelą cię w stopę. +1Nie mam wystarczającej reputacji, aby komentować, więc dodam to do innych odpowiedzi.
Jon Skeet odpowiada doskonale, z pięknym przykładem. Matt B ma rację: nie wszystkie superklasy mają supers. Twój kod pękłby, gdybyś nazwał super super, który nie miał super.
Programowanie obiektowe (którym jest Java) dotyczy obiektów, a nie funkcji. Jeśli chcesz programować zadania, wybierz C ++ lub coś innego. Jeśli twój obiekt nie mieści się w jego superklasie, musisz dodać go do „klasy dziadka”, utworzyć nową klasę lub znaleźć inną super-klasę, do której pasuje.
Osobiście uważam to ograniczenie za jedną z największych zalet Javy. Kod jest nieco sztywny w porównaniu do innych języków, których używałem, ale zawsze wiem, czego się spodziewać. Pomaga to w „prostym i znanym” celu Java. Moim zdaniem wywołanie super.super nie jest proste ani znajome. Być może programiści czuli to samo?
źródło
Jest kilka dobrych powodów, aby to zrobić. Możesz mieć podklasę, która ma niepoprawnie zaimplementowaną metodę, ale metoda nadrzędna jest zaimplementowana poprawnie. Ponieważ należy on do biblioteki innej firmy, możesz nie być w stanie / nie chcieć zmienić źródła. W takim przypadku chcesz utworzyć podklasę, ale zastąp jedną metodę, aby wywołać metodę super.super.
Jak pokazują niektóre inne plakaty, można to zrobić poprzez refleksję, ale powinno być możliwe zrobienie czegoś podobnego
(SuperSuperClass this) .theMethod ();
Mam teraz do czynienia z tym problemem - szybka poprawka polega na skopiowaniu i wklejeniu metody nadklasy do metody podklasy :)
źródło
Oprócz bardzo dobrych uwag innych, myślę, że istnieje jeszcze jeden powód: co jeśli superklasa nie ma superklasy?
Ponieważ każda klasa naturalnie się rozszerza (przynajmniej)
Object
,super.whatever()
zawsze będzie odnosić się do metody w nadklasie. Ale co, jeśli twoja klasa się przedłużyObject
- do czego bysuper.super
się wtedy odnosiło? Jak należy obsługiwać to zachowanie - błąd kompilatora, wskaźnik NullPointer itp.?Myślę, że głównym powodem, dla którego jest to niedozwolone, jest naruszenie enkapsulacji, ale może to być również niewielki powód.
źródło
Myślę, że jeśli nadpiszesz metodę i chcesz ją wszystkich w
equals
superklasycznej wersji (np. Powiedzmy za ), to praktycznie zawsze chcesz najpierw wywołać bezpośrednią wersję superklasy, która z kolei wywoła jej wersję superklasy, jeśli chce .Myślę, że rzadko ma to sens (jeśli w ogóle. Nie mogę wymyślić przypadku, w którym tak się dzieje), aby wywołać dowolną wersję metody nadklasy. Nie wiem, czy jest to w ogóle możliwe w Javie. Można to zrobić w C ++:
źródło
Zgaduję, ponieważ nie jest tak często używany. Jedynym powodem, dla którego mogłem to zobaczyć, jest to, że twój bezpośredni rodzic zastąpił niektóre funkcje i próbujesz przywrócić je z powrotem do oryginału.
To wydaje mi się sprzeczne z zasadami OO, ponieważ bezpośredni rodzic klasy powinien być bliżej związany z twoją klasą niż dziadek.
źródło
Spójrz na ten projekt Github, zwłaszcza zmienna objectHandle. Ten projekt pokazuje, jak właściwie i dokładnie wywołać metodę dziadka u wnuka.
Na wypadek, gdyby link się zepsuł, oto kod:
Happy Coding !!!!
źródło
W miarę możliwości umieściłem treść metody super.super w innej metodzie
Lub jeśli nie możesz zmienić klasy super-super, możesz spróbować:
W obu przypadkach
wyniki do „Jestem super super”
źródło
Wydaje się, że można przynajmniej uzyskać klasę nadklasy nadklasy, choć niekoniecznie jej instancję, używając refleksji; jeśli może to być przydatne, rozważ Javadoc pod adresem http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass ()
źródło
run: A BUILD SUCCESSFUL (całkowity czas: 0 sekund)
źródło
Wywołanie super.super.method () ma sens, gdy nie można zmienić kodu klasy bazowej. Zdarza się to często podczas rozszerzania istniejącej biblioteki.
Najpierw zadaj sobie pytanie, dlaczego poszerzasz tę klasę? Jeśli odpowiedź brzmi „ponieważ nie mogę tego zmienić”, możesz utworzyć dokładny pakiet i klasę w swojej aplikacji oraz przepisać niegrzeczną metodę lub utworzyć delegata:
Na przykład możesz utworzyć klasę org.springframework.test.context.junit4.SpringJUnit4ClassRunner w swojej aplikacji, aby klasa ta została załadowana przed prawdziwą klasą ze słoika. Następnie przepisz metody lub konstruktory.
Uwaga: Jest to absolutny hack i zdecydowanie NIE zaleca się jego używania, ale DZIAŁA! Korzystanie z tego podejścia jest niebezpieczne ze względu na możliwe problemy z modułami ładującymi klasy. Może to również powodować problemy przy każdej aktualizacji biblioteki zawierającej zastąpioną klasę.
źródło
Miałem takie sytuacje, gdy architektura ma budować wspólną funkcjonalność we wspólnej CustomBaseClass, która implementuje w imieniu kilku klas pochodnych. Musimy jednak obejść wspólną logikę dla konkretnej metody dla określonej klasy pochodnej. W takich przypadkach musimy użyć implementacji super.super.methodX.
Osiągamy to poprzez wprowadzenie elementu logicznego w CustomBaseClass, którego można użyć do selektywnego odroczenia niestandardowej implementacji i uzyskania domyślnej implementacji frameworka, gdy jest to pożądane.
Jednak dzięki dobrym zasadom architektury stosowanym zarówno w środowisku, jak i aplikacji, moglibyśmy łatwo uniknąć takich sytuacji, stosując podejście hasA zamiast podejścia isA. Ale przez cały czas nie jest zbyt praktyczne oczekiwanie na dobrze zaprojektowaną architekturę, a zatem potrzeba odejścia od solidnych zasad projektowania i wprowadzenia takich hacków. Tylko moje 2 centy ...
źródło
@Jon Skeet Ładne wyjaśnienie. IMO, jeśli ktoś chce wywołać metodę super.super, to musi chcieć zignorować zachowanie bezpośredniego rodzica, ale chce uzyskać dostęp do zachowania dziadka. Można to osiągnąć poprzez instancję. Jak poniżej kod
Oto klasa kierowców,
Wynik tego będzie
W tym przypadku zachowanie klasy B printClass zostanie zignorowane. Nie jestem pewien, czy jest to idealna lub dobra praktyka, aby osiągnąć super. Super, ale nadal działa.
źródło
Jeśli uważasz, że potrzebujesz superklasy, możesz odwoływać się do niej w zmiennej dla tej klasy. Na przykład:
Powinien wydrukować:
źródło
new UltraFoo.getNumber()
nie będę się kompilować, ponieważ przegapiłeś tam nawiasy. Jednak właśnie usunąłem moją donację, ponieważ koncepcja twojego kodu jest teraz całkiem jasna, dzięki!IMO to czysty sposób na
super.super.sayYourName()
zachowanie w Javie.Wynik:
Request to lie: d.sayYourName(true) returns Grandma Fedora
Request not to lie: d.sayYourName(false) returns Little girl Masha
źródło
Myślę, że jest to problem, który łamie umowę spadkową.
Rozszerzając klasę, jesteś posłuszny / zgadzasz się na jego zachowanie, cechy
Podczas gdy podczas rozmowy
super.super.method()
chcesz złamać własną umowę posłuszeństwa.Po prostu nie możesz wybrać z super klasy .
Mogą się jednak zdarzyć sytuacje, gdy poczujesz potrzebę połączenia
super.super.method()
- zwykle zły znak projektowy, w kodzie lub w odziedziczonym kodzie!Jeśli super i super super klasy nie mogą być refaktoryzowane (niektóre starsze kody), to wybierz kompozycję zamiast dziedziczenia. Przerwanie
enkapsulacji ma miejsce, gdy @Opinie się nad niektórymi metodami przez zerwanie enkapsulowanego kodu. Metody, których nie można zastąpić, są oznaczone jako ostateczne .
źródło
W języku C # możesz wywołać metodę dowolnego przodka takiego jak ten:
Możesz to również zrobić w Delphi:
Ale w Javie możesz skupić się tylko na niektórych urządzeniach. Jednym z możliwych sposobów jest:
wynik wyniku objC.DoIt ():
źródło
To jest po prostu łatwe do zrobienia. Na przykład:
Podklasa C z podklasy B i B z A. Obie trzy mają na przykład metodę methodName ().
Uruchomienie klasy C Wyjście będzie: Klasa A Klasa C
Zamiast wyjścia: Klasa A Klasa B Klasa C
źródło
Wyjście: wydrukowano w GrandDad
źródło
super.super.method()
nie jest prawidłowy kod w Javie.Słowo kluczowe super jest tylko sposobem na wywołanie metody w nadklasie. W samouczku Java: https://docs.oracle.com/javase/tutorial/java/IandI/super.html
Jeśli metoda zastępuje jedną z metod jej nadklasy, można wywołać zastąpioną metodę za pomocą słowa kluczowego super.
Nie wierz, że to odniesienie do super obiektu !!! Nie, to tylko słowo kluczowe do wywoływania metod w nadklasie.
Oto przykład:
Gdy zadzwonisz
cat.doSth()
, metodadoSth()
w klasieAnimal
wydrukujethis
i jest to kot.źródło