get și set (getteri și setteri) în Kotlin

Clase și obiecte Kotlin 1.0

get și set definesc ce se întâmplă când o proprietate este citită sau modificată; field este valoarea păstrată în spate.

Sintaxă
val proprietate: Tip
    get() = calcul

var proprietate: Tip = valoare
    set(value) { field = value }     // field = valoarea păstrată
    private set                      // se modifică doar din clasă

Ce face get și set (getteri și setteri)

Orice proprietate Kotlin are un getter (rulează la citire) și, dacă este var, un setter (rulează la atribuire). Implicit ei doar citesc și scriu valoarea. Îi poți rescrie sub declarație: get() = ... calculează valoarea la fiecare citire, iar set(value) { ... } poate valida sau transforma valoarea primită.

În setter (și în getter), valoarea păstrată se numește field (backing field). Scrii field = value, nu pret = value: atribuirea către proprietate ar apela din nou setterul, la nesfârșit.

Poți schimba vizibilitatea setterului fără să-l rescrii: var sold = 0; private set înseamnă că oricine poate citi soldul, dar doar clasa îl poate modifica.

Exemple

Exemplul 1: Getter calculat

numeComplet și majora nu păstrează nimic: se calculează la fiecare citire, deci urmăresc schimbările.

class Persoana(var prenume: String, var nume: String, var varsta: Int) {
    val numeComplet: String
        get() = "$prenume $nume"

    val majora get() = varsta >= 18
}

fun main() {
    val p = Persoana("Ioana", "Marin", 17)
    println("${p.numeComplet}, majoră: ${p.majora}")
    p.varsta = 18
    p.nume = "Pop"
    println("${p.numeComplet}, majoră: ${p.majora}")
}

Rezultat

Ioana Marin, majoră: false
Ioana Pop, majoră: true

Exemplul 2: Setter cu validare și field

Setterul refuză notele în afara intervalului 1-10 și păstrează valoarea veche. field este valoarea memorată.

class Nota(valoareInitiala: Int) {
    var valoare: Int = valoareInitiala
        set(value) {
            if (value in 1..10) {
                field = value
            } else {
                println("Nota $value este invalidă, rămâne $field")
            }
        }
}

fun main() {
    val n = Nota(7)
    n.valoare = 9
    println("Nota: ${n.valoare}")
    n.valoare = 15
    println("Nota: ${n.valoare}")
}

Rezultat

Nota: 9
Nota 15 este invalidă, rămâne 9
Nota: 9

Exemplul 3: private set

vizite se citește din afară, dar se modifică doar prin metoda inregistreaza. Setterul personalizat de la oras transformă textul la fiecare atribuire.

class Pagina(val adresa: String) {
    var vizite = 0
        private set

    var oras: String = ""
        set(value) { field = value.trim().replaceFirstChar { it.uppercase() } }

    fun inregistreaza() { vizite++ }
}

fun main() {
    val p = Pagina("/invata/kotlin/")
    repeat(3) { p.inregistreaza() }
    p.oras = "  timișoara "
    println("${p.adresa}: ${p.vizite} vizite din ${p.oras}")
}

Rezultat

/invata/kotlin/: 3 vizite din Timișoara

Greșeli frecvente

  • Scrierea set(value) { pret = value }: setterul se apelează pe el însuși la infinit și programul se oprește cu StackOverflowError. Folosește field = value.
  • Un getter calculat cu inițializare (val x: Int = 5 get() = 10): dacă getterul nu folosește field, nu există valoare de inițializat (eroare initializer is prohibited here because this property has no backing field).
  • Calcule scumpe în get(): rulează la fiecare citire. Pentru o valoare calculată o singură dată folosește by lazy.

Comenzi înrudite

  • val și var: val declară o variabilă care nu mai poate fi schimbată după atribuire; var declară una care poate primi altă valoare.
  • class: class declară o clasă: un tip nou care grupează date (proprietăți) și comportament (metode).
  • lateinit: lateinit permite unei proprietăți var ne-nullable să primească valoare mai târziu, după crearea obiectului.
  • Proprietăți delegate (by lazy, observable, map): O proprietate delegată (val x by …) lasă un alt obiect să decidă ce se întâmplă la citire și scriere: lazy, observable, map.
  • private și protected: private ascunde o declarație în clasa sau fișierul ei; protected o face vizibilă și în subclase.