Funcția de extensie în Kotlin: ce este, sintaxa și aplicare

Autor: IT Sectr Publicat: 2026-06-21 Timp de citire: 9 min

funcția de extensie — mecanismul Kotlin care permite adăugarea de noi metode la clase existente fără moștenire și fără modificarea codului sursă. Funcția este declarată cu un prefix de tip receptor și este apelată ca o metodă obișnuită a acestui tip. Potrivit Kotlin Documentation, 2025, funcțiile de extensie sunt compilate în metode statice cu primul parametru receptor, ceea ce garantează suprasarcină zero în runtime în comparație cu apelurile obișnuite.

Principalele

  • Funcția de extensie — metodă cu tip receptor, apelată ca membru al clasei fără moștenire
  • Tipul receptor este indicat prin punct înaintea numelui funcției: fun Type.method()
  • Dispecerizare statică — funcția de extensie nu este virtuală, se apelează după tipul variabilei
  • Importul este obligatoriu: funcțiile de extensie nu sunt membri ai clasei și necesită import
  • Membrii clasei au prioritate: dacă metoda coincide — se apelează membrul clasei, nu extensia

Ce este funcția de extensie în Kotlin?

Funcția de extensie este o funcție declarată în afara clasei, dar apelată ca metodă a acesteia. Ea primește un tip receptor la care se adaugă o nouă metodă. În interiorul funcției, cuvântul cheie this se referă la instanța tipului receptor. Această abordare permite extinderea claselor finale, a claselor din biblioteci terțe și chiar a tipurilor primitive fără a crea învelitori.

Spre deosebire de Java, unde pentru a adăuga o metodă la o clasă existentă este necesară fie moștenirea, fie o clasă utilitară statică, Kotlin oferă o soluție elegantă fără boilerplate. Potrivit datelor cercetării Kotlin Foundation (2024), funcțiile de extensie se află în primele cinci cele mai utilizate caracteristici ale limbajului — 78% dintre dezvoltatorii Kotlin le folosesc în munca de zi cu zi.

Compilatorul Kotlin transformă funcția de extensie într-o metodă statică, unde primul argument este instanța receptorului. Aceasta înseamnă că funcțiile de extensie nu modifică bytecodul clasei țintă și nu încalcă încapsularea — sunt accesibile doar câmpurile și metodele publice ale receptorului.

Folosiți funcțiile de extensie pentru a scrie funcții utilitare curate care sunt legate logic de un anumit tip, dar nu pot fi adăugate în codul său sursă.

Sintaxa funcției de extensie: declarare și apelare

Sintaxa de bază a funcției de extensie: numele tipului receptor, punct, numele funcției, apoi parametrii și tipul de returnare. În interiorul funcției, receptorul este accesibil prin this.

kotlin
// Funcție de extensie pentru String
fun String.isEmail(): Boolean {
    return this.contains("@") && this.contains(".")
}

// Apelată ca metodă obișnuită String
val result = "user@example.com".isEmail() // true

În acest exemplu, isEmail() devine disponibil pentru toate șirurile. În interiorul funcției, this este însuși șirul pentru care se apelează metoda. Kotlin permite omiterea lui this în majoritatea cazurilor — se poate scrie pur și simplu contains("@") în loc de this.contains("@").

Funcția de extensie cu parametri

Funcțiile de extensie pot primi parametri suplimentari și pot returna valori de orice tip. Acest lucru le face funcții complete, nu doar zahăr sintactic.

kotlin
fun List<Int>.defaultIfEmpty(default: Int): List<Int> {
    if (this.isEmpty()) return listOf(default)
    return this
}

val populated = listOf(1, 2).defaultIfEmpty(0)
val empty = listOf<Int>().defaultIfEmpty(0)

Parametrul default determină valoarea returnată pentru o listă goală. Funcția de extensie poate fi generică — tipul List este generalizat, deși în exemplu se folosește List concret.

Dispecerizare statică și receptor

Funcțiile de extensie în Kotlin folosesc dispecerizare statică, nu virtuală. Aceasta este diferența cheie față de metodele obișnuite ale claselor. Care funcție de extensie va fi apelată se determină în faza de compilare după tipul static al variabilei, nu după tipul ei real în runtime.

kotlin
open class Animal
class Dog : Animal()

fun Animal.speak() = "Sunet animal"
fun Dog.speak() = "Ham"

fun test() {
    val animal: Animal = Dog()
    println(animal.speak()) // „Sunet animal” — tip static Animal

    val dog: Dog = Dog()
    println(dog.speak()) // „Ham” — tip static Dog
}

Deși variabila animal indică o instanță Dog, se apelează funcția de extensie pentru Animal, deoarece tipul static al variabilei este Animal. Dacă speak() ar fi o metodă virtuală a clasei, s-ar apela Dog.speak(). Această proprietate este importantă de luat în considerare la proiectarea API-urilor bazate pe funcții de extensie.

Importul și domeniul de vizibilitate al funcțiilor de extensie

Funcțiile de extensie nu sunt membri ai clasei — sunt funcții obișnuite care necesită import pentru a fi utilizate în alt fișier. Kotlin oferă două variante de import: după numele funcției sau cu redenumire.

kotlin
// Import după nume
import com.example.extensions.isEmail

// Import cu alias (pentru a rezolva conflictele)
import com.example.extensions.isEmail as isValidEmail

// Apel după import
val valid = "test@test.com".isEmail()

Redenumirea prin as este utilă în caz de conflicte de nume — de exemplu, dacă două biblioteci oferă o funcție de extensie cu același nume pentru același tip. În acest caz, se poate importa una dintre ele cu un alt nume și se poate apela prin noul nume.

Domeniul de vizibilitate

Funcțiile de extensie pot fi declarate la diferite niveluri:

NivelVizibilitateExemplu
Top-levelÎntregul proiect după importfun String.isEmail()
Member extensionÎn interiorul clasei proprietarclass A { fun B.ext() }
LocalÎn interiorul funcțieifun test() { fun String.ext() }

Member extension functions — caz special când funcția de extensie este declarată în interiorul altei clase. În acest caz, în interiorul funcției de extensie sunt accesibili atât receptorul (this al funcției), cât și membrii clasei exterioare.

Prioritatea membrilor clasei față de extensii

Dacă clasa are o metodă cu aceeași semnătură ca funcția de extensie, se apelează întotdeauna membrul clasei. Funcția de extensie nu suprascrie niciodată metoda clasei — este o decizie arhitecturală pentru a preveni suprascrierile accidentale.

kotlin
class User {
    fun greet() = "Salut din clasă"
}

fun User.greet() = "Hello from extension"

fun main() {
    val user = User()
    println(user.greet()) // „Salut din clasă”
}

Chiar dacă funcția de extensie este definită mai târziu și are aceeași semnătură, compilatorul va alege metoda clasei. Compilatorul Kotlin emite un avertisment la detectarea unei astfel de situații. Singura modalitate de a apela funcția de extensie în prezența metodei clasei este de a se adresa ei ca unei funcții obișnuite: greet(user).

Exemple practice de funcții de extensie

În dezvoltarea Android, funcțiile de extensie au devenit un instrument standard pentru lucrul cu View, Context și fragmente. Biblioteca Android KTX este construită pe funcții de extensie, oferind învelitori convenabile pentru API-ul Android.

kotlin
// Funcție de extensie pentru lucrul cu View
fun View.show() {
    visibility = View.VISIBLE
}

fun View.hide() {
    visibility = View.GONE
}

// Funcție de extensie pentru Context — toast
fun Context.toast(message: String) {
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}

// Funcție de extensie ca constructor DSL
fun String.colorFormat(color: String): String =
    "$color$this\u001b[0m"

Funcția de extensie toast() face apelurile dependente de Context concise: în loc să scrieți Toast.makeText(context, message, length).show() este suficient să scrieți context.toast("Text"). Aceasta reduce boilerplate-ul și face codul mai lizibil.

Întrebări frecvente

Se poate suprascrie o funcție de extensie într-o subclasă?

Nu, funcțiile de extensie folosesc dispecerizare statică. Dacă declarați o funcție de extensie pentru clasa de bază și una similară pentru subclasă, care dintre ele va fi apelată se determină de tipul static al variabilei în faza de compilare, nu de tipul real în runtime.

Cum funcționează funcțiile de extensie cu tipurile nullable?

Se pot declara funcții de extensie pentru tipuri receptor nullable: fun String?.isNullOrEmail(). În interiorul unei astfel de funcții, this poate fi null, de aceea este necesar să folosiți operatori de apelare sigură sau verificare explicită de null.

Au funcțiile de extensie suprasarcină de performanță?

Nu, funcțiile de extensie sunt compilate în metode statice. La nivel de bytecod, apelul unei funcții de extensie este identic cu apelul unei metode statice cu primul parametru receptor. Nici o reflecție sau dispecerizare dinamică.

Se poate declara o proprietate de extensie pentru o clasă?

Da, proprietățile de extensie funcționează similar cu funcțiile de extensie, dar nu pot stoca stare — doar getter și setter. De exemplu: val List<Int>.sum get() = reduce(Int::plus). Ele sunt de asemenea compilate în metode statice getter/setter.

Prin ce diferă funcțiile de extensie de metodele din clasele utilitare Java?

În Java scrieți StringUtils.isEmail(str), iar în Kotlin — str.isEmail(). Diferența nu este doar de sintaxă: funcțiile de extensie suportă autocompletarea în IDE, îmbunătățesc lizibilitatea lanțurilor de apeluri și permit IDE-ului să sugereze funcții relevante pentru un anumit tip. În Java astfel de posibilități nu există.

Rezumat

  • Funcția de extensie — metodă cu tip receptor, apelată ca membru al clasei fără moștenire
  • Dispecerizare statică — selectarea funcției după tipul static, nu după tipul de runtime
  • Suprasarcină zero — compilată în metodă statică cu receptorul ca prim parametru
  • Importul obligatoriu pentru utilizare în alte fișiere, alias posibil prin as
  • Membrii clasei au prioritate față de funcțiile de extensie cu aceeași semnătură
  • Member extensions — extensii declarate în interiorul clasei, au acces la membrii săi
  • Aplicare practică — utilitare pentru String, View, Context, colecții și construire DSL

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și