English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Dans cet article, vous allez apprendre l'héritage . Plus précisément, qu'est-ce que l'héritage et comment l'implémenter en Kotlin en utilisant l'héritage (par exemple) .
L'héritage est l'une des fonctionnalités clés de la programmation orientée objet (OOP) . Il permet aux utilisateurs de créer une nouvelle classe (classe dérivée) à partir d'une classe existante (classe de base) .
Les classes dérivées héritent de toutes les fonctionnalités de la classe de base et peuvent avoir leurs propres autres fonctionnalités .
Avant de détailler l'héritage en Kotlin, il est recommandé de lire les deux articles suivants :
hypothétiquement, si dans votre application vous avez besoin de trois rôles-unprofesseur de mathématiques(MathTeacher), unfootballeur(Footballer) et unun homme d'affaires (Businessman).
Comme tous les rôles sont des humains, ils peuvent marcher et parler . Mais ils ont également des compétences spéciales . Un professeur de mathématiques peutenseigner la mathématique (teachMath)et un footballeur peutjouer au football(playFootball), un homme d'affaires peutgérer une entreprise (runBusiness).
Vous pouvez créer trois classes distinctes qui peuvent marcher, parler et exécuter leurs compétences spéciales .
Dans chaque classe, vous allez copier le même code de marche et de parole pour chaque rôle .
Si vous souhaitez ajouter de nouvelles fonctionnalités - Pour manger (eat), il faut répéter le même code pour chaque rôle . Cela peut facilement entraîner des erreurs (dans les copies) et des codes redondants .
Si nous avons une classe Personne avec des fonctionnalités de base, par exemple, marcher, manger, dormir, et d'ajouter des compétences spéciales pour ces fonctions en fonction de notre rôle, cela serait plus facile . Cela est réalisé par l'héritage .
En utilisant l'héritage, vous n'avez pas besoin de répéter le code walk() , talk() et eat() pour chaque classe . Vous n'avez besoin que dehéritageC'est tout .
Par conséquent, pour MathTeacher (classe dérivée), vous pouvez hériter de toutes les fonctionnalités de Personne (classe de base) et ajouter une nouvelle fonction teachingMath() . De même, pour la classe Footballer, vous héritez de toutes les fonctionnalités de la classe Personne et ajoutez une nouvelle fonction playFootball() , et ainsi de suite .
Ce qui rend votre code plus concis, compréhensible et extensible .
Il est important de se souvenir :Lorsque l'on traite de l'héritage, chaque classe dérivée doit satisfaire les conditions de son type de "classe de base" . Dans l'exemple précédent, MathTeacher est une Personne (homme), Footballer est une Personne (homme) . Vous ne pouvez pas penser que "un homme d'affaires (Businessman) est une entreprise (Business)" .
Essayons de réaliser ce qui a été discuté dans le code :
ouvert classe Person(age: Int) { //Code pour manger, parler, marcher } class MathTeacher(age: Int): Person(age) { //Autres caractéristiques du professeur de mathématiques } class Footballer(age: Int): Person(age) { //Autres caractéristiques du footballeur } class Businessman(age: Int): Person(age) { // Autres caractéristiques du businessman }
Ici, Person est la classe de base, tandis que les classes MathTeacher, Footballer et Businessman sont dérivées de la classe Person.
Notez que la clé open est précédée de la classe de base Person, ce qui est très important.
Par défaut, les classes en Kotlin sont finales. Si vous êtes familier avec Java, vous savez que les classes finales ne peuvent pas être héritées. En utilisant l'annotation sur la classe, le compilateur permet de dériver de nouvelles classes.
class Person(age: Int, name: String) { init { println("Mon nom est $name.") println("Mon âge est $age") } } class MathTeacher(age: Int, name: String): Person(age, name) { fun teachMaths() { println("Je donne des cours à l'école primaire.") } } class Footballer(age: Int, name: String): Person(age, name) { fun playFootball() { println("Je joue pour le Los Angeles Galaxy.") } } fun main(args: Array<String>) { val t1 = MathTeacher(25, "Jack") t1.teachMaths() println() val f1 = Footballer(29, "Christiano") f1.playFootball() }
La sortie de l'exécution du programme est :
Mon nom est Jack. Mon âge est 25 Je donne des cours à l'école primaire. Mon nom est Cristiano. Mon âge est 29 Je joue pour le Los Angeles Galaxy.
Ici, deux classes MathTeacher et Footballer sont dérivées de la classe Person.
Le constructeur principal de la classe Person déclare deux attributs : age et name, et possède un bloc d'initialisation. Les objets des classes dérivées de Person (MathTeacher et Footballer) peuvent accéder au bloc d'initialisation (et aux fonctions membres) de la classe de base.
Les classes dérivées MathTeacher et Footballer ont leurs propres fonctions membres teachMaths() et playFootball(). Ces fonctions ne peuvent être accédées que depuis les objets de leurs classes respectives.
lors de la création de l'objet de la classe MathTeacher t1 lorsque
val t1 = MathTeacher(25, "Jack")
les paramètres sont passés au constructeur principal. Dans Kotlin, lors de la création d'un objet, le bloc init est appelé. Comme MathTeacher est dérivé de la classe Person, il recherche le bloc d'initialisation dans la classe de base (Person) et l'exécute. Si MathTeacher a un bloc init, le compilateur exécute également le bloc init de la classe dérivée.
ensuite, en utilisant t1.teachMaths() appelle la méthode teachMaths() de l'objet t1.appeler la fonction teachMaths() de l'objet t
crée un objet de la classe f1 lorsque, le fonctionnement du programme est similaire. Il exécute le bloc init de la classe de base. Ensuite, l'instruction f1.playFootball() appelle la méthode playFootball() de la classe Footballer.
Si la classe a un constructeur principal, il est nécessaire d'utiliser les paramètres du constructeur principal pour initialiser la classe de base. Dans le programme ci-dessus, deux classes dérivées ont deux paramètres age et name, et ces deux paramètres sont tous deux initialisés dans le constructeur principal de la classe de base.
Voici un autre exemple :
class Person(age: Int, name: String) { // quelques codes } class Footballer(age: Int, name: String, club: String): Person(age, name) { init { println("L'athlète de football âgé de $age, $name, joue pour $club.") } fun playFootball() { println("Je suis en train de jouer au football.") } } fun main(args: Array<String>) { val f1 = Footballer(29, "Cristiano", "LA Galaxy") }
Dans ce cas, le constructeur principal de la classe dérivée a3paramètres, tandis que la classe de base a2paramètres. Veuillez noter que les deux paramètres de la classe de base sont déjà initialisés.
Si il n'y a pas de constructeur principal, chaque classe de base doit initialiser la classe de base (en utilisant le mot-clé super), ou déléguer à un autre constructeur qui effectue cette opération. Par exemple
fun main(args: Array<String>) { val p1 = AuthLog("Mauvais mot de passe") } ouvrir la classe Log { var data: String = "" var numberOfData = 0 constructor(_data: String) { } constructor(_data: String, _numberOfData: Int) { data = _data numberOfData = _numberOfData println("$data: $numberOfData fois") } } class AuthLog: Log { constructor(_data: String): this("From AuthLog -> + $_data", 10) { } constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) { } }
Pour en savoir plus sur le fonctionnement de ce programme, visitezConstructeur secondaire Kotlin.
Si la classe de base et la classe dérivée contiennent des fonctions membres (ou des propriétés) portant le même nom, il peut être nécessaire d'utiliser le mot-clé override pour redéfinir la fonction membre de la classe dérivée et utiliser le mot-clé open pour la fonction membre de la classe de base.
// Constructeur principal vide open class Person() { open fun displayAge(age: Int) { println("Mon âge est $age.") } } class Girl: Person() { override fun displayAge(age: Int) {}} println("Mon âge virtuel est ${age - 5}.") } } fun main(args: Array<String>) { val girl = Girl() girl.displayAge(31) }
La sortie de l'exécution du programme est :
l'âge virtuel est 26.
Ici, girl.displayAge(31) Appel de la méthode displayAge() de la classe dérivée Girl.
Vous pouvez également utiliser une méthode similaire pour surcharger les propriétés de la classe de base.
Avant d'apprendre les exemples suivants, vous pouvez accéder à Getter et setter en Kotlin Voyons comment cela fonctionne.
//Constructeur principal vide open class Person() { open var age: Int = 0 get() = field set(value) { field = value } } class Girl: Person() { override var age: Int = 0 get() = field set(value) { field = value - 5 } } fun main(args: Array<String>) { val girl = Girl() girl.age = 31 println("Mon âge virtuel est ${girl.age}.") }
La sortie de l'exécution du programme est :
Mon âge virtuel est 26.
Comme vous le voyez, nous avons utilisé les mots-clés override et open pour l'attribut age dans les classes dérivée et de base.
Vous pouvez utiliser la clé de mots-clés super pour appeler les fonctions de la classe de base à partir de la classe dérivée (et accéder aux propriétés). Voici comment faire :
open class Person() { open fun displayAge(age: Int) { println("Mon âge réel est $age.") } } class Girl: Person() { override fun displayAge(age: Int) {}} //Appel de la fonction de la classe mère super.displayAge(age) println("Mon âge virtuel est ${age - 5}.") } } fun main(args: Array<String>) { val girl = Girl() girl.displayAge(31) }
La sortie de l'exécution du programme est :
Mon âge réel est 31. Mon âge virtuel est 26.