programowanieSenior Kotlin Developer

Jak działa słowo kluczowe 'super' w Kotlinie i czym różni się jego użycie w Javie? W jakich przypadkach mogą wystąpić trudności z niejednoznacznością przy wielokrotnej realizacji interfejsów i jak je rozwiązać?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

W Kotlinie słowo kluczowe super jest używane do odwołania się do realizacji metody lub właściwości klasy nadrzędnej lub realizowanego interfejsu. W odróżnieniu od Javy, Kotlin pozwala na wyraźne wskazanie, przez który interfejs lub klasę wywołać realizację metody, co jest szczególnie ważne w przypadku "konfliktu" kilku interfejsów z takimi samymi metodami.

Cechą charakterystyczną: Jeśli klasa realizuje kilka interfejsów, w których zdefiniowana jest metoda o tej samej sygnaturze i istnieje domyślna realizacja, to należy wyraźnie wskazać, którą realizację wykorzystać.

Przykład:

interface A { fun foo() = println("A") } interface B { fun foo() = println("B") } class C : A, B { override fun foo() { super<A>.foo() // Wyraźne wywołanie A.foo super<B>.foo() // Wyraźne wywołanie B.foo } }

Nie jest to obsługiwane w Javie bezpośrednio (Java nie zezwala na posiadanie przez interfejs pola/realizacji metod do Javy 8, a nawet w Javie 8 — mechanizmy są inne).

Pytanie z podwójnym dnem

"Czy w Kotlinie można odwołać się do realizacji metody klasy nadrzędnej przez kilka poziomów dziedziczenia?"

  • Częsta pomyłka: myśli się, że można odwołać się do realizacji przez klasę pośrednią: super<Intermediate>.foo(), ale tak nie jest — można odwołać się tylko do bezpośredniej klasy nadrzędnej lub interfejsu, który realizuje daną metodę bezpośrednio.

Przykład:

open class Base { open fun foo() = println("Base") } open class Mid : Base() { override fun foo() { println("Mid"); super.foo() } } class Child: Mid() { override fun foo() { super.foo() // wywoła Mid.foo() // super<Base>.foo() — błąd kompilacji } }

Przykłady rzeczywistych błędów spowodowanych niewiedzą na temat niuansów tematu


Historia

W dużym projekcie interfejsy Logger i Auditor oba definiowały metodę record(). Podczas realizacji klasy, która dziedziczyła oba interfejsy, programista nie nadpisał jawnie record(), w efekcie pojawił się błąd kompilacji "Klasa musi nadpisać publiczną otwartą funkcję record()". Musiał zrealizować metodę ręcznie i jawnie delegować do odpowiedniego interfejsu.


Historia

Podczas próby wywołania zrealizowanej metody klasy nadrzędnej przez kilka pośrednich warstw (np. super<Base>.foo()), wystąpił błąd kompilacji. Programista nie znał ograniczeń Kotlina i nie mógł zrozumieć, dlaczego bezpośrednie wywołanie jest niemożliwe.


Historia

Po aktualizacji API jeden z interfejsów dodał realizację funkcji domyślnej, która pokrywała się z innym interfejsem. Stary kod przestał się kompilować z powodu konfliktu realizacji — trzeba było jawnie rozwiązać konflikt, realizując metodę samodzielnie i wybierając, które realizacje superinterfejsów wywoływać wewnątrz siebie.