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-unHashSetsauHashMap. - Recursivitate accidentală: în
override fun f() = f() + 1se apelează tot metoda suprascrisă; ai vrutsuper.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.