Come sono organizzate l'ereditarietà e il polimorfismo in Kotlin?
sobes.tech AI
Risposta dell'AI
In Kotlin, l'ereditarietà è implementata attraverso meccanismi di classi e interfacce. Le classi possono ereditare solo da un'altra classe (ereditarietà singola), ma possono implementare più interfacce.
Per impostazione predefinita, tutte le classi in Kotlin sono 'finali', cioè non possono essere ereditate. Per consentire l'ereditarietà, una classe deve essere esplicitamente contrassegnata con la parola chiave open.
Ereditarietà delle classi:
open class Shape { // Classe base, contrassegnata come open
open fun draw() { // Metodo che può essere sovrascritto
println("Disegnare una forma")
}
}
class Circle : Shape() { // Eredita da Shape
override fun draw() { // Sovrascrive il metodo
println("Disegnare un cerchio")
}
}
Nel costruttore della classe figlia, è necessario chiamare esplicitamente o implicitamente il costruttore della classe base.
Interfacce:
Le interfacce in Kotlin sono simili a quelle di Java 8 e possono contenere metodi astratti e metodi con implementazione. Le classi possono implementare una o più interfacce.
interface Drawable {
fun draw() // Metodo astratto
fun description() { // Metodo con implementazione di default
println("Questo è un oggetto disegnabile")
}
}
class Square : Drawable {
override fun draw() { // Implementazione del metodo astratto
println("Disegnare un quadrato")
}
// description() può essere sovrascritto, ma non è obbligatorio
}
Polimorfismo:
Il polimorfismo in Kotlin si ottiene grazie alla possibilità di lavorare con oggetti di classi diverse tramite un tipo base comune (classe o interfaccia). Questo permette di chiamare metodi specifici del tipo reale dell'oggetto durante l'esecuzione.
fun render(drawable: Drawable) {
drawable.draw() // Chiamata al metodo draw() in base al tipo effettivo dell'oggetto
drawable.description()
}
fun main() {
val circle: Shape = Circle() // L'oggetto Circle viene trattato come Shape
circle.draw() // Chiamata a draw() di Circle grazie al polimorfismo
val square: Drawable = Square() // L'oggetto Square viene trattato come Drawable
render(square) // Chiamata a draw() e description() di Square
}
In questo esempio, render lavora con qualsiasi oggetto che implementa Drawable. La chiamata a drawable.draw() eseguirà l'implementazione del metodo draw per il tipo specifico dell'oggetto (Square in questo caso).
Differenze tra ereditarietà di classi e implementazione di interfacce:
- Ereditarietà di classe: Stabilisce una relazione "è un" (is-a). La classe figlia eredita lo stato e il comportamento della classe base.
- Implementazione di interfacce: Definisce una "capacità" o "contratto". La classe promette di fornire l'implementazione di tutti i metodi astratti dell'interfaccia.
Tabella di confronto:
| Caratteristica | Ereditarietà di classe | Implementazione di interfaccia |
|---|---|---|
| Tipo di relazione | è-a | Capacità / Contratto |
| Múltiple | Singola | Multipla |
| Stato | Eredita lo stato della classe base | Non eredita stato |
| Implementazione metodi | Può contenere implementazione | Può contenere implementazione di default (da Java 8) |