Kotlin : ereditarietà
In Kotlin tutte le classi derivano da un’unica super-classe Any la quale ha tre metodi : equals(), hashCode() e toString() che quindi risultato essere definiti per ogni classe di Kotlin. Di default ogni classe non è ereditabile. Per renderla ereditabile deve essere definita come aperta utilizzando la keyword open. Un esempio di ereditarietà è riportata qui sotto:
open class Base(p: Int)
class Derived(p: Int) : Base(p)
in cui il parametro p della classe derivata viene passato al costruttore della classe base. Questo deve essere sempre fatto se la classe derivata ha un costruttore primario. Se invece la classe derivata non ha un costruttore primario, allora ogni costruttore secondario deve inizializzare il costruttore della classe base utilizzando la keyword super :
class MyView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}
Anche i metodi che possono essere overridati devono essere dichiarati esplicitamente con la keyword open. L’override poi dovrà essere dichiarato utilizzando esplicitamente la keyword override. Un metodo dichiarato come override può essere a sua volta overridato. Per evitare ciò è necessario aggiungere la keyword final. Esempio di classico processo di override :
open class Shape {
open fun draw() { /*...*/ }
fun fill() { /*...*/ }
}
class Circle() : Shape() {
override fun draw() { /*...*/ }
}
mentre un caso in cui il metodo draw non deve più essere overridato :
open class Rectangle() : Shape() {
final override fun draw() { /*...*/ }
}
Ovviamente è possibile overridare anche delle proprietà allo stesso modo in cui si overrida un metodo. Una variabile di tipo val (costante) può essere overridata da una variabile di tipo var ma ovviamente non vale il viceversa. L’override può essere fatto anche nel costruttore principale come mostrato nel seguente esempio:
interface Shape {
val vertexCount: Int
}
class Rectangle(override val vertexCount: Int = 4) : Shape
class Polygon : Shape {
override var vertexCount: Int = 0
}
Quando viene istanziata una classe derivata, l’inizializzazione della classe base viene effettuata prima di quella derivata. Questo significa che quando viene eseguito il costruttore della classe base, le proprietà dichiarate nella classe derivata non sono state ancora inizializzate. Per evitare errori runtime o comportamenti imprevisti è sempre consigliato non usare membri open nel costruttore della classe base, nell’inizializzazione delle proprietà o nel blocco init.
Il codice in una classe derivata può chiamare dei metodi e proprietà della classe base utilizzando la keyword super. Un esempio è:
open class Rectangle {
open fun draw() { println("Drawing a rectangle") }
val borderColor: String get() = "black"
}
class FilledRectangle : Rectangle() {
override fun draw() {
super.draw()
println("Filling the rectangle")
}
val fillColor: String get() = super.borderColor
}
In generale, in Kotlin implementare l’editarietà deve seguire la seguente regola: “Se una classe eredita multiple implementazioni dello stesso membro dalla sua immediata super-classe, essa deve overridare questo membro e fornire la sua implementazione. La keyword super nel caso di ereditarietà multiple è sostituita dalla super<ClasseBase> come mostrato nell’esempio:
open class Rectangle {
open fun draw() { /* ... */ }
}
interface Polygon {
fun draw() { /* ... */ }
}
class Square() : Rectangle(), Polygon {
override fun draw() {
super<Rectangle>.draw()
super<Polygon>.draw()
}
}
Commenti recenti