interface în Kotlin

Moștenire, interfețe și vizibilitate Kotlin 1.0 (fun interface: Kotlin 1.4)

interface descrie ce poate face un obiect (metode și proprietăți), fără stare; o clasă poate implementa mai multe interfețe.

Sintaxă
interface Nume {
    val proprietate: Tip            // abstractă
    fun metoda(): Tip               // abstractă
    fun altaMetoda() = ...          // cu implementare implicită
}

class X : Nume, AltaInterfata { override ... }

fun interface Regula { fun verifica(x: Int): Boolean }

Ce face interface

O interfață este un contract: spune ce metode și proprietăți are un tip, iar clasele care o implementează scriu codul. Clasa o declară după : (class Card : MetodaPlata) și scrie fiecare membru abstract cu override. Codul care primește o MetodaPlata funcționează cu orice clasă care o implementează.

Spre deosebire de o clasă, o interfață nu poate ține stare (câmpuri cu valori), dar poate avea metode cu implementare implicită și proprietăți declarate (abstracte sau cu get()). O clasă poate implementa oricâte interfețe, dar poate moșteni o singură clasă.

fun interface (interfață funcțională, Kotlin 1.4+) are o singură metodă abstractă și poate fi creată direct dintr-o lambda: val pozitiv = Regula { it > 0 } (conversie SAM).

Exemple

Exemplul 1: O interfață, mai multe implementări

plateste primește o listă de MetodaPlata și nu știe ce clasă concretă are fiecare. descriere() are o implementare implicită, suprascrisă doar de Card.

interface MetodaPlata {
    val nume: String
    fun comision(suma: Double): Double
    fun descriere() = "Plată prin $nume"
}

class Card(val ultimeleCifre: String) : MetodaPlata {
    override val nume = "card"
    override fun comision(suma: Double) = suma * 0.015
    override fun descriere() = "Card care se termină în $ultimeleCifre"
}

class Numerar : MetodaPlata {
    override val nume = "numerar"
    override fun comision(suma: Double) = 0.0
}

fun main() {
    val metode = listOf(Card("4321"), Numerar())
    for (m in metode) {
        println("${m.descriere()}: comision ${m.comision(200.0)} lei")
    }
}

Rezultat

Card care se termină în 4321: comision 3.0 lei
Plată prin numerar: comision 0.0 lei

Exemplul 2: O clasă care implementează două interfețe

Telefon este și Incarcabil, și Conectabil, deci poate fi dat ambelor funcții și poate sta într-o listă de Conectabil.

interface Incarcabil { fun incarca(procent: Int): String }
interface Conectabil { val retea: String; fun conecteaza() = "Conectat la $retea" }

class Telefon(override val retea: String) : Incarcabil, Conectabil {
    override fun incarca(procent: Int) = "Bateria este la $procent%"
}

fun laPriza(d: Incarcabil) = println(d.incarca(100))
fun peWifi(d: Conectabil) = println(d.conecteaza())

fun main() {
    val t = Telefon("Acasa-5G")
    laPriza(t)
    peWifi(t)
    val dispozitive: List<Conectabil> = listOf(t, Telefon("Birou"))
    println("Rețele: ${dispozitive.map { it.retea }}")
}

Rezultat

Bateria este la 100%
Conectat la Acasa-5G
Rețele: [Acasa-5G, Birou]

Exemplul 3: fun interface creată dintr-o lambda

Regula are o singură metodă abstractă, deci fiecare regulă se scrie ca o lambda.

fun interface Regula {
    fun verifica(parola: String): Boolean
}

fun main() {
    val reguli = mapOf(
        "minim 8 caractere" to Regula { it.length >= 8 },
        "conține o cifră" to Regula { p -> p.any { it.isDigit() } },
        "conține o majusculă" to Regula { p -> p.any { it.isUpperCase() } },
    )
    for (parola in listOf("ana2026", "Iasi2026!")) {
        val incalcate = reguli.filterValues { !it.verifica(parola) }.keys
        println("$parola: ${if (incalcate.isEmpty()) "OK" else "lipsește: $incalcate"}")
    }
}

Rezultat

ana2026: lipsește: [minim 8 caractere, conține o majusculă]
Iasi2026!: OK

Greșeli frecvente

  • Inițializarea unei proprietăți în interfață (val nume = "x"): eroare property initializers in interfaces are prohibited. Folosește val nume: String get() = "x".
  • Uitarea lui override la implementare: eroare 'x' hides member of supertype 'MetodaPlata' and needs an 'override' modifier.
  • Paranteze după numele interfeței: class A : MetodaPlata() este greșit; interfețele nu au constructor. Parantezele se pun doar după o clasă de bază.

Comenzi înrudite

  • abstract: abstract marchează o clasă care nu poate fi creată direct și membri fără implementare, pe care subclasele trebuie să-i scrie.
  • override și super: override înlocuiește o metodă sau o proprietate moștenită; super apelează versiunea din clasa de bază sau din interfață.
  • by (delegare): by trimite implementarea unei interfețe către alt obiect (delegare de clasă) sau citirea unei proprietăți către un delegat.
  • object: object declară o clasă cu un singur obiect (singleton) sau creează pe loc un obiect anonim care implementează o interfață.
  • sealed class și sealed interface: sealed declară o ierarhie închisă: toate subtipurile sunt cunoscute la compilare, deci when le poate verifica pe toate fără else.