Ce face private și protected
private pe un membru al unei clase înseamnă că doar codul din acea clasă îl poate folosi. Este felul obișnuit de a ascunde starea internă (de exemplu soldul unui cont), ca ea să se schimbe doar prin metode care verifică regulile. O declarație private la nivelul de sus al fișierului (funcție, clasă, proprietate) este vizibilă doar în acel fișier.
protected se folosește doar în clase: membrul este vizibil în clasă și în subclasele ei, dar nu și din exterior. Spre deosebire de Java, protected în Kotlin nu dă acces celorlalte clase din același pachet.
Un membru override păstrează vizibilitatea din bază dacă nu o schimbi. Poți face privat doar setterul unei proprietăți: var sold = 0; private set.
Exemple
Exemplul 1: private în clasă și în fișier
sold se schimbă doar prin depune/retrage. formateaza este privată în fișier: o folosește doar codul de aici.
private fun formateaza(suma: Int) = "%,d lei".format(java.util.Locale.ROOT, suma).replace(',', '.')
class Cont(val titular: String) {
private var sold = 0
private val istoric = mutableListOf<String>()
fun depune(suma: Int) {
sold += suma
istoric.add("+$suma")
}
fun retrage(suma: Int) {
if (suma <= sold) { sold -= suma; istoric.add("-$suma") } else istoric.add("refuzat $suma")
}
fun extras() = "$titular: ${formateaza(sold)} (${istoric.joinToString()})"
}
fun main() {
val cont = Cont("Ana Pop")
cont.depune(12_500)
cont.retrage(3_000)
cont.retrage(50_000)
println(cont.extras())
// cont.sold = 1_000_000 // eroare: cannot access 'var sold: Int': it is private in 'Cont'
}
Rezultat
Ana Pop: 9.500 lei (+12500, -3000, refuzat 50000)
Exemplul 2: protected: vizibil în subclase
Notificare pune la dispoziția subclaselor metoda antet, dar codul din main nu o poate apela.
abstract class Notificare(protected val destinatar: String) {
protected fun antet() = "Către $destinatar"
abstract fun trimite(): String
}
class Email(adresa: String) : Notificare(adresa) {
override fun trimite() = "${antet()} | email trimis"
}
class Sms(telefon: String) : Notificare(telefon) {
override fun trimite() = "${antet()} | SMS trimis la ${destinatar.takeLast(4)}"
}
fun main() {
val lista = listOf(Email("ana@exemplu.ro"), Sms("0722123456"))
lista.forEach { println(it.trimite()) }
// lista[0].antet() // eroare: cannot access 'fun antet(): String': it is protected in 'Notificare'
}
Rezultat
Către ana@exemplu.ro | email trimis
Către 0722123456 | SMS trimis la 3456
Exemplul 3: Mesajul compilatorului pentru un membru privat
Codul din afara clasei încearcă să scrie direct în sold. Compilarea se oprește cu eroarea de mai jos (exact asta s-ar întâmpla și dacă ai scoate comentariul din primul exemplu).
class Cont(val titular: String) {
private var sold = 0
fun depune(suma: Int) { sold += suma }
}
fun main() {
val cont = Cont("Ana Pop")
cont.depune(100)
cont.sold = 1_000_000
}
Rezultat la compilare
main.kt:9:10: error: cannot access 'var sold: Int': it is private in 'Cont'.
cont.sold = 1_000_000
^^^^
Greșeli frecvente
- Așteptarea ca
protectedsă dea acces în tot pachetul, ca în Java: în Kotlin dă acces doar subclaselor. protectedla nivelul de sus al fișierului: nu este permis (nu există o clasă de moștenit).- Ascunderea unei liste
private valdar returnarea ei directă (fun lista() = istoric): codul din afară primește aceeașiMutableListși o poate modifica. Returneazăistoric.toList().
Comenzi înrudite
public și internal: public (implicit) face o declarație vizibilă oriunde; internal o face vizibilă doar în modulul în care este scrisă.class: class declară o clasă: un tip nou care grupează date (proprietăți) și comportament (metode).get și set (getteri și setteri): get și set definesc ce se întâmplă când o proprietate este citită sau modificată; field este valoarea păstrată în spate.abstract: abstract marchează o clasă care nu poate fi creată direct și membri fără implementare, pe care subclasele trebuie să-i scrie.open și final: În Kotlin clasele și metodele sunt final implicit; open permite moștenirea sau suprascrierea, iar final o oprește din nou.