Redéfinition des membres
Fait partie de la section Programmation orientée objet du Journey Kotlin de Coddy. Leçon 18 sur 57.
Une sous-classe peut remplacer une méthode héritée par sa propre version. La superclasse marque la méthode avec open, et la sous-classe la déclare à nouveau avec override :
open class Animal(val name: String) {
open fun sound() = "..."
}
class Dog(name: String) : Animal(name) {
override fun sound() = "Woof"
}
class Cat(name: String) : Animal(name) {
override fun sound() = "Meow"
}À l’intérieur de main :
println(Dog("Rex").sound())
println(Cat("Tom").sound())
println(Animal("Generic").sound())Sortie :
Woof
Meow
...La version qui s’exécute est choisie par la classe réelle de l’objet, même lorsque le type de la variable est la superclasse. Le code à l’intérieur de la superclasse qui appelle une méthode ouverte obtient également la version de la sous-classe :
open class Animal(val name: String) {
open fun sound() = "..."
fun speak() = "$name says ${sound()}"
}
class Dog(name: String) : Animal(name) {
override fun sound() = "Woof"
}À l’intérieur de main :
val pets: List<Animal> = listOf(Dog("Rex"), Animal("Generic"))
for (p in pets) println(p.speak())Sortie :
Rex says Woof
Generic says ...Les propriétés peuvent être redéfinies de la même manière : open val dans la superclasse, override val dans la sous-classe, soit comme propriété normale, propriété de constructeur ou accesseur calculé :
open class Shape {
open val name = "shape"
open val corners = 0
}
class Triangle : Shape() {
override val name = "triangle"
override val corners = 3
}
class Polygon(override val corners: Int) : Shape() {
override val name: String
get() = "$corners-gon"
}À l'intérieur de main :
for (s in listOf(Shape(), Triangle(), Polygon(6))) println("${s.name}: ${s.corners}")Sortie :
shape: 0
triangle: 3
6-gon: 6Un membre marqué override est de nouveau ouvert, de sorte qu’une sous-classe de la sous-classe peut encore le remplacer une fois ; final override l’en empêche. Un membre sans open ne peut pas du tout être remplacé, et une sous-classe ne peut pas déclarer de membre ayant la même signature :
open class Animal {
open fun sound() = "..."
fun sleep() = "zzz"
}
open class Dog : Animal() {
final override fun sound() = "Woof"
}
class Puppy : Dog() {
// override fun sound() = "Yip" // erreur : 'sound' dans 'Dog' est final
// fun sleep() = "nap" // erreur : 'sleep' masque un membre de la superclasse
}Défi
FacileAnimal possède legs() (4), sound() (...) et describe(), qui renvoie Rex has 4 legs and says Woof, construit à partir de legs() et sound(). Rendez legs() et sound() surchargeables et complétez les sous-classes en ne surchargeant que ces deux méthodes : Dog dit Woof, Bird a 2 pattes et dit Tweet, et Snake a 0 patte et dit Hiss. describe() reste tel quel dans Animal.
Le code fourni lit les lignes dog,Rex, bird,Pip, snake,Kaa ou tout autre type (un simple Animal), stocke les animaux dans une seule List<Animal> et affiche describe() pour chacun.
Votre code va dans Animal.kt, Dog.kt, Bird.kt et Snake.kt. Main.kt contient le code d'entrée/sortie fourni et ne peut pas être modifié.
Essayez vous-même
fun main() {
// Code d'entrée/sortie fourni : le garder tel quel
val input = generateSequence(::readLine).toList()
val animals = mutableListOf<Animal>()
for (line in input) {
val (kind, name) = line.split(",")
animals.add(when (kind) {
"dog" -> Dog(name)
"bird" -> Bird(name)
"snake" -> Snake(name)
else -> Animal(name)
})
}
for (a in animals) println(a.describe())
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Classes et objets
Travailler avec des fichiersDéfinir des classesConstructeurs primairesBlocs init et validationConstructeurs secondairesRécapitulatif - Carte de bibliothèque4Héritage
Classes ouvertes et sous-classesRedéfinition des membressuper et constructeursClasses abstraitesRécapitulatif – Annuaire du personnel2Propriétés et encapsulation
Accesseurs personnalisésModificateurs de visibilitéSetters privéslazy et lateinitRécapitulatif - Compte bancaire5Interfaces
Déclarer des interfacesMéthodes par défautInterfaces multiplesInterfaces en tant que typesRécapitulatif - Méthodes de paiement8Génériques
Fonctions génériquesClasses génériquesContraintes de typeVariance avec in et outRécapitulatif - File de priorité11Projet : Gestion de bibliothèque
Livres et membresEmprunter des livresEntraînez-vous par vous-même : Playground Kotlin