ProgrammatieSenior Kotlin Ontwikkelaar

Hoe werkt het keyword 'super' in Kotlin en hoe verschilt het van het gebruik in Java? In welke gevallen ontstaan er problemen met ambiguïteit bij meervoudige interface-implementaties en hoe los je die op?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

In Kotlin wordt het keyword super gebruikt om naar de implementatie van een methode of eigenschap van de superklasse of de geïmplementeerde interface te verwijzen. In tegenstelling tot Java stelt Kotlin je in staat om expliciet aan te geven via welke interface of klasse je de methode-implementatie wilt aanroepen, wat vooral belangrijk is bij 'conflicten' van meerdere interfaces met dezelfde methoden.

Kenmerk: Als een klasse meerdere interfaces implementeert waarin een methode met dezelfde handtekening gedefinieerd is en er een standaardimplementatie is, dan moet je expliciet aangeven welke implementatie je wilt gebruiken.

Voorbeeld:

interface A { fun foo() = println("A") } interface B { fun foo() = println("B") } class C : A, B { override fun foo() { super<A>.foo() // Explicit aanroepen A.foo super<B>.foo() // Explicit aanroepen B.foo } }

Dit wordt in Java niet direct ondersteund (Java staat interfaces niet toe om velden/methode-implementaties te hebben tot Java 8, en zelfs in Java 8 — de mechanismen zijn anders).

Vraag met een addertje onder het gras

"Is het mogelijk om in Kotlin naar de implementatie van een methode van de superklasse te verwijzen via meerdere niveaus van overerving?"

  • Veelgemaakte fout: men denkt dat men kan verwijzen naar de implementatie via een tussenklasse: super<Intermediate>.foo(), maar dat is niet zo — je kunt alleen verwijzen naar de directe superklasse of interface, waarvan die bepaalde methode direct is geïmplementeerd.

Voorbeeld:

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() // roept Mid.foo() aan // super<Base>.foo() — compilatiefout } }

Voorbeelden van echte fouten door onwetendheid over de nuances van het onderwerp


Verhaal

In een groot project definieerden de interfaces Logger en Auditor beide de methode record(). Bij het implementeren van een klasse die beide interfaces erfde, had de programmeur record() niet expliciet geherdefinieerd, waardoor de compilatiefout "Klas moet de publieke open functie record() overschrijven" ontstond. De methode moest handmatig worden geïmplementeerd en expliciet aan de betreffende interface worden gedelegeerd.


Verhaal

Bij het proberen om de geïmplementeerde methode van de superklasse aan te roepen via meerdere tussenliggende lagen (bijv. super<Base>.foo()), ontstond er een compilatiefout. De ontwikkelaar kende de beperkingen van Kotlin niet en begreep niet waarom de directe aanroep onmogelijk was.


Verhaal

Na een API-update had een van de interfaces een standaardfunctie-implementatie toegevoegd, die samenviel met een andere interface. Oude code compileerde niet meer vanwege het conflict van implementaties — men moest het conflict expliciet oplossen door de methode zelf te implementeren en te kiezen welke implementaties van superinterfaces binnen zichzelf moesten worden aangeroepen.