override și super în Kotlin

override înlocuiește o metodă sau o proprietate moștenită; super apelează versiunea din clasa de bază sau din interfață.

Sintaxă
override fun metoda() { super.metoda(); ... }
override val proprietate = ...
override fun toString() = ...

super<InterfataA>.metoda()      // când două tipuri de bază au aceeași metodă

Ce face override și super

Când o clasă implementează un membru dintr-o interfață sau schimbă un membru open din clasa de bază, trebuie să scrie override. Cuvântul este obligatoriu: dacă lipsește, compilatorul dă eroare, iar dacă îl scrii pe o metodă care nu există în bază (de exemplu din cauza unei greșeli de scriere), tot primești eroare. Toate clasele moștenesc din Any metodele toString(), equals() și hashCode(), care pot fi suprascrise.

super.metoda() apelează versiunea din clasa de bază, ca să o extinzi în loc s-o rescrii complet. Dacă o clasă moștenește aceeași metodă din două locuri (o clasă și o interfață, sau două interfețe), trebuie să o suprascrie și poate alege cu super<Tip>.metoda().

Un val poate fi suprascris cu val sau var, dar un var nu poate deveni val. Constructorul unei subclase apelează constructorul bazei în antet: class B(x: Int) : A(x).

Exemple

Exemplul 1: Extinderea unei metode cu super

Premium păstrează mesajul din bază și adaugă la el. toString este suprascris pentru afișare.

open class Abonament(val client: String) {
    open fun beneficii() = listOf("acces la articole")
    override fun toString() = "Abonament($client): ${beneficii().joinToString()}"
}

class Premium(client: String) : Abonament(client) {
    override fun beneficii() = super.beneficii() + listOf("fără reclame", "cursuri video")
}

fun main() {
    println(Abonament("Ana"))
    println(Premium("Mihai"))
}

Rezultat

Abonament(Ana): acces la articole
Abonament(Mihai): acces la articole, fără reclame, cursuri video

Exemplul 2: Aceeași metodă din două interfețe: super

Ambele interfețe au descriere(), deci Smartwatch trebuie s-o suprascrie și le apelează pe amândouă.

interface Ceas { fun descriere() = "arată ora" }
interface Telefon { fun descriere() = "primește apeluri" }

class Smartwatch : Ceas, Telefon {
    override fun descriere() = "Smartwatch: ${super<Ceas>.descriere()} și ${super<Telefon>.descriere()}"
}

fun main() {
    println(Smartwatch().descriere())
}

Rezultat

Smartwatch: arată ora și primește apeluri

Exemplul 3: override val și equals

roti este suprascrisă ca proprietate. equals și hashCode sunt suprascrise ca două plăcuțe cu același număr să fie egale.

open class Vehicul { open val roti: Int = 4 }
class Bicicleta : Vehicul() { override val roti = 2 }

class Placuta(val numar: String) {
    override fun equals(other: Any?) = other is Placuta && other.numar.replace(" ", "") == numar.replace(" ", "")
    override fun hashCode() = numar.replace(" ", "").hashCode()
}

fun main() {
    val vehicule = listOf(Vehicul(), Bicicleta())
    println(vehicule.map { it.roti })
    println(Placuta("IS 10 ABC") == Placuta("IS10ABC"))
    println(setOf(Placuta("B 01 XYZ"), Placuta("B01XYZ")).size)
}

Rezultat

[4, 2]
true
1

Greșeli frecvente

  • Lipsa lui override: eroare 'x' hides member of supertype 'Y' and needs an 'override' modifier.
  • Suprascrierea doar a lui equals, fără hashCode: obiectele egale ajung în locuri diferite într-un HashSet sau HashMap.
  • Recursivitate accidentală: în override fun f() = f() + 1 se apelează tot metoda suprascrisă; ai vrut super.f() + 1.

Comenzi înrudite

  • open și final: În Kotlin clasele și metodele sunt final implicit; open permite moștenirea sau suprascrierea, iar final o oprește din nou.
  • interface: interface descrie ce poate face un obiect (metode și proprietăți), fără stare; o clasă poate implementa mai multe interfețe.
  • abstract: abstract marchează o clasă care nu poate fi creată direct și membri fără implementare, pe care subclasele trebuie să-i scrie.
  • data class: data class este o clasă pentru date: primește automat toString, equals, hashCode, copy și componentN.
  • this: this înseamnă obiectul curent: obiectul pe care s-a apelat metoda sau receptorul unei funcții de extensie.