Ce face inner class
O clasă scrisă în interiorul altei clase este, implicit, doar imbricată (nested): numele ei este grupat sub clasa exterioară (Magazin.Adresa), dar nu are acces la un obiect anume al clasei exterioare. Se creează cu Magazin.Adresa(...). Este echivalentul lui static class din Java.
Cu inner class, fiecare obiect interior aparține unui obiect exterior și îi poate folosi proprietățile și metodele (inclusiv cele private). Se creează pornind de la un obiect exterior: magazin.Raion("Lactate"). Pentru a ajunge explicit la obiectul exterior scrii this@Magazin.
Un obiect inner ține obiectul exterior în memorie cât timp trăiește el. Folosește inner doar când ai nevoie de acces la exterior.
Exemple
Exemplul 1: Clasă imbricată și clasă inner
Adresa nu vede nume. Raion este inner, deci folosește direct nume al magazinului din care a fost creat.
class Magazin(val nume: String) {
class Adresa(val oras: String, val strada: String) {
fun text() = "$strada, $oras"
}
inner class Raion(val denumire: String) {
fun eticheta() = "$nume - raionul $denumire"
}
}
fun main() {
val adresa = Magazin.Adresa("Iași", "Str. Păcurari 5")
println(adresa.text())
val mega = Magazin("Mega Iași")
val lactate = mega.Raion("Lactate")
println(lactate.eticheta())
}
Rezultat
Str. Păcurari 5, Iași
Mega Iași - raionul Lactate
Exemplul 2: Clasa inner modifică starea exteriorului
Fiecare Rand adaugă la totalul facturii din care face parte. this@Factura arată clar că totalul este al facturii.
class Factura(val numar: String) {
private var total = 0.0
private val randuri = mutableListOf<Rand>()
inner class Rand(val produs: String, val cantitate: Int, val pret: Double) {
init {
this@Factura.total += cantitate * pret
randuri.add(this)
}
}
fun tipareste() {
println("Factura $numar")
for (r in randuri) println(" ${r.produs} x${r.cantitate} = ${r.cantitate * r.pret}")
println(" Total: $total lei")
}
}
fun main() {
val f = Factura("F-2026-17")
f.Rand("Caiet", 3, 4.5)
f.Rand("Pix", 2, 2.0)
f.tipareste()
}
Rezultat
Factura F-2026-17
Caiet x3 = 13.5
Pix x2 = 4.0
Total: 17.5 lei
Greșeli frecvente
- Folosirea membrilor clasei exterioare dintr-o clasă imbricată fără
inner: eroareouter class 'class Magazin' of non-inner class cannot be used as receiver. - Crearea unei clase
innerfără obiect exterior:Magazin.Raion("x")nu compilează; trebuiemagazin.Raion("x"). - Marcarea cu
innerdin obișnuință: obiectele inner țin în viață obiectul exterior. Dacă nu ai nevoie de acces, las-o imbricată.
Comenzi înrudite
class: class declară o clasă: un tip nou care grupează date (proprietăți) și comportament (metode).this: this înseamnă obiectul curent: obiectul pe care s-a apelat metoda sau receptorul unei funcții de extensie.object: object declară o clasă cu un singur obiect (singleton) sau creează pe loc un obiect anonim care implementează o interfață.private și protected: private ascunde o declarație în clasa sau fișierul ei; protected o face vizibilă și în subclase.