kiterjesztési függvény — Kotlin mechanizmus, amely lehetővé teszi új metódusok hozzáadását meglévő osztályokhoz öröklés nélkül és a forráskód módosítása nélkül. A függvény egy fogadó típusú előtaggal deklarálódik, és e típus szokásos metódusaként hívódik meg. A Kotlin Documentation, 2025 szerint a kiterjesztési függvények statikus metódusokká fordulnak az első fogadó paraméterrel, ami nulla többletterhelést garantál futásidőben a szokásos hívásokhoz képest.
Főbb pontok
A kiterjesztési függvény egy olyan függvény, amely az osztályon kívül van deklarálva, de annak metódusaként hívódik meg. Elfogad egy fogadó típust, amelyhez új metódus kerül hozzáadásra. A függvényen belül a this kulcsszó a fogadó típus példányára hivatkozik. Ez a megközelítés lehetővé teszi végleges osztályok, harmadik fél könyvtárainak osztályai, sőt primitív típusok kiterjesztését is burkolók létrehozása nélkül.
A Javától eltérően, ahol egy metódus hozzáadása egy meglévő osztályhoz vagy öröklést, vagy statikus segédosztályt igényel, a Kotlin elegáns megoldást kínál boilerplate nélkül. Adatok szerint a Kotlin Foundation (2024) kutatása szerint a kiterjesztési függvények a nyelv öt leggyakrabban használt funkciója közé tartoznak — a Kotlin fejlesztők 78%-a használja őket napi munkájában.
A Kotlin fordító a kiterjesztési függvényt statikus metódussá alakítja, ahol a fogadó példány első argumentumként kerül átadásra. Ez azt jelenti, hogy a kiterjesztési függvények nem változtatják meg a célosztály bájtkódját és nem sértik meg az egységbezárást — csak a fogadó nyilvános mezői és metódusai érhetők el.
Használja a kiterjesztési függvényeket tiszta segédfüggvények írásához, amelyek logikailag egy adott típushoz kötődnek, de nem adhatók hozzá a forráskódjához.
A kiterjesztési függvény alap szintaxisa: fogadó típus neve, pont, függvény neve, majd paraméterek és visszatérési típus. A függvényen belül a fogadó a this segítségével érhető el.
// Kiterjesztési függvény Stringhez
fun String.isEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
// Szokásos String metódusként hívva
val result = "user@example.com".isEmail() // true
Ebben a példában az isEmail() elérhetővé válik minden string számára. A függvényen belül a this maga a string, amelyen a metódus hívódik. A Kotlin a legtöbb esetben lehetővé teszi a this elhagyását — egyszerűen írhat contains("@") a this.contains("@") helyett.
A kiterjesztési függvények további paramétereket fogadhatnak és bármilyen típusú értéket visszaadhatnak. Ez teljes értékű függvényekké teszi őket, nem csupán szintaktikai cukorrá.
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)
A default paraméter meghatározza az üres lista esetén visszaadott értéket. A kiterjesztési függvény lehet generikus — a List
A Kotlin kiterjesztési függvényei statikus diszpécserezést használnak, nem virtuálisat. Ez a legfontosabb különbség a szokásos osztálymetódusoktól. Az, hogy melyik kiterjesztési függvény kerül meghívásra, a fordítási fázisban a változó statikus típusa alapján kerül meghatározásra, nem pedig a futásidőbeli tényleges típusa alapján.
open class Animal
class Dog : Animal()
fun Animal.speak() = "Állathang"
fun Dog.speak() = "Ugatás"
fun test() {
val animal: Animal = Dog()
println(animal.speak()) // „Állathang” — statikus típus Animal
val dog: Dog = Dog()
println(dog.speak()) // „Ugatás” — statikus típus Dog
}
Bár a változó animal egy Dog példányra mutat, az Animal kiterjesztési függvény hívódik, mert a változó statikus típusa Animal. Ha a speak() az osztály virtuális metódusa lenne, a Dog.speak() hívódna. Ez a tulajdonság fontos figyelembe venni a kiterjesztési függvényeken alapuló API-k tervezésekor.
A kiterjesztési függvények nem osztálytagok — ezek szokásos függvények, amelyek importálást igényelnek egy másik fájlban való használathoz. A Kotlin két importálási változatot kínál: függvény név szerint vagy átnevezéssel.
// Importálás név szerint
import com.example.extensions.isEmail
// Importálás aliasszal (konfliktusok megoldásához)
import com.example.extensions.isEmail as isValidEmail
// Hívás importálás után
val valid = "test@test.com".isEmail()
Az átnevezés as segítségével névütközések esetén hasznos — például ha két könyvtár ugyanazzal a névvel kínál kiterjesztési függvényt ugyanahhoz a típushoz. Ebben az esetben az egyik másik néven importálható és az új néven keresztül hívható.
A kiterjesztési függvények különböző szinteken deklarálhatók:
| Szint | Láthatóság | Példa |
|---|---|---|
| Top-level | Teljes projekt importálás után | fun String.isEmail() |
| Member extension | A tulajdonos osztályon belül | class A { fun B.ext() } |
| Local | Függvényen belül | fun test() { fun String.ext() } |
Member extension functions — speciális eset, amikor a kiterjesztési függvény egy másik osztályon belül van deklarálva. Ebben az esetben a kiterjesztési függvényen belül mind a fogadó (a függvény this-je), mind a külső osztály tagjai elérhetők.
Ha az osztálynak van olyan metódusa, amelynek aláírása megegyezik a kiterjesztési függvényével, mindig az osztálytag hívódik. A kiterjesztési függvény soha nem írja felül az osztály metódusát — ez egy architekturális döntés a véletlen felülírások megelőzésére.
class User {
fun greet() = "Helló az osztályból"
}
fun User.greet() = "Hello from extension"
fun main() {
val user = User()
println(user.greet()) // „Helló az osztályból”
}
Még ha a kiterjesztési függvény később kerül is meghatározásra és ugyanazzal az aláírással rendelkezik, a fordító az osztály metódusát választja. A Kotlin fordító figyelmeztetést ad egy ilyen helyzet észlelésekor. Az egyetlen mód a kiterjesztési függvény meghívására osztálymetódus jelenlétében, ha szokásos függvényként hivatkozunk rá: greet(user).
Az Android fejlesztésben a kiterjesztési függvények szabványos eszközzé váltak a View, Context és fragmentumok kezelésére. Az Android KTX könyvtár kiterjesztési függvényekre épül, kényelmes burkolókat biztosítva az Android API-hoz.
// Kiterjesztési függvény View-val való munkához
fun View.show() {
visibility = View.VISIBLE
}
fun View.hide() {
visibility = View.GONE
}
// Kiterjesztési függvény Contexthez — toast
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
// Kiterjesztési függvény DSL építőként
fun String.colorFormat(color: String): String =
"$color$this\u001b[0m"
A toast() kiterjesztési függvény tömörré teszi a Context-től függő hívásokat: a Toast.makeText(context, message, length).show() írás helyett elég context.toast("Szöveg")-et írni. Ez csökkenti a boilerplate-et és olvashatóbbá teszi a kódot.
Gyakran Ismételt Kérdések
Nem, a kiterjesztési függvények statikus diszpécserezést használnak. Ha deklarál egy kiterjesztési függvényt az alaposztályhoz és ugyanazt az alosztályhoz, hogy melyik hívódik meg, azt a változó statikus típusa határozza meg a fordítási fázisban, nem a futásidőbeli tényleges típus.
Lehetőség van kiterjesztési függvények deklarálására nullable fogadó típusokhoz: fun String?.isNullOrEmail(). Egy ilyen függvényen belül a this lehet null, ezért biztonságos hívás operátorokat vagy explicit null ellenőrzést kell használni.
Nem, a kiterjesztési függvények statikus metódusokká fordulnak. Bájtkód szinten a kiterjesztési függvény hívása megegyezik egy statikus metódus hívásával az első fogadó paraméterrel. Nincs reflexió vagy dinamikus diszpécserezés.
Igen, a kiterjesztési tulajdonságok hasonlóan működnek a kiterjesztési függvényekhez, de nem tárolhatnak állapotot — csak getter és setter. Például: val List<Int>.sum get() = reduce(Int::plus). Ezek is statikus getter/setter metódusokká fordulnak.
Java-ban StringUtils.isEmail(str)-et ír, Kotlinban — str.isEmail()-t. A különbség nem csak a szintaxisban van: a kiterjesztési függvények támogatják az automatikus kiegészítést az IDE-ben, javítják a hívási láncok olvashatóságát és lehetővé teszik az IDE számára, hogy releváns függvényeket javasoljon egy adott típushoz. Java-ban ilyen lehetőségek nincsenek.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is