Kotlin est un langage de programmation moderne qui compile en bytecode Java. C'est gratuit et open source, et promet de rendre le codage pour Android encore plus amusant.
Dans l'article précédent, vous en avez appris davantage sur les propriétés de Kotlin, telles que les propriétés d'initialisation tardive, d'extension et en-ligne. De plus, vous avez également découvert les classes avancées telles que les classes data, enum, imbriquées et scellées dans Kotlin..
Dans cet article, vous allez continuer à vous familiariser avec la programmation orientée objet dans Kotlin en vous renseignant sur les classes abstraites, les interfaces et l'héritage. Pour un bonus, vous apprendrez également sur les alias de type.
Kotlin supporte les classes abstraites - tout comme Java, ce sont des classes pour lesquelles vous n'avez jamais l'intention de créer des objets. Une classe abstraite est incomplète ou inutile sans certaines sous-classes concrètes (non abstraites), à partir desquelles vous pouvez instancier des objets. Une sous-classe concrète d'une classe abstraite implémente toutes les méthodes et propriétés définies dans la classe abstraite. Sinon, la sous-classe est également une classe abstraite.!
Nous créons une classe abstraite avec le abstrait
modificateur (similaire à Java).
Classe abstraite Employé (val firstName: String, val lastName: String) résumé amusant gains (): Double
Notez que tous les membres ne doivent pas nécessairement être abstraits. En d'autres termes, nous pouvons avoir une implémentation par défaut de la méthode dans une classe abstraite.
classe abstraite Employé (val firstName: String, val lastName: String) //… fun nom complet (): String return lastName + "" + firstName;
Ici nous avons créé la fonction non abstraite nom complet()
dans une classe abstraite Employé
. Les classes concrètes (sous-classes de la classe abstraite) peuvent redéfinir l'implémentation par défaut d'une méthode abstraite, mais uniquement si la méthode a ouvrir
modificateur spécifié (vous en apprendrez plus à ce sujet prochainement).
Nous pouvons également stocker l'état dans des classes abstraites.
Classe abstraite Employé (val firstName: String, val lastName: String) //… val propFoo: String = "bla bla"
Même si la classe abstraite ne définit aucune méthode, nous devons créer une sous-classe avant de pouvoir l'instancier, comme dans l'exemple ci-dessous..
programmeur de classe (prénom: chaîne, nom de famille: chaîne): employé (prénom, nom de famille) ignore les gains intéressants (): double // calcule les gains
Notre Programmeur
la classe étend la Employé
classe abstraite. En Kotlin, nous utilisons un seul caractère deux-points (:
) au lieu de Java s'étend
mot clé pour étendre une classe ou implémenter une interface.
On peut alors créer un objet de type Programmeur
et appelez des méthodes dessus, soit dans sa propre classe, soit dans la superclasse (classe de base).
val programmer = Programmeur ("Chike", "Mgbemena") println (programmer.fullName ()) // "Mgbemena Chike"
Une chose qui pourrait vous surprendre est que nous avons la possibilité de passer outre un val
(immuable) propriété avec var
(mutable).
classe ouverte BaseA (open val baseProp: String) classe DerivedA: BaseA ("") var privée private DeriveProp: String = "" substitue var BaseProp: String get () = DeriveProp set (valeur) DerileProp = valeur
Assurez-vous d'utiliser cette fonctionnalité à bon escient! Sachez que nous ne pouvons pas inverser la priorité var
propriété avec val
.
Une interface est simplement un ensemble de méthodes associées qui vous permettent généralement d'indiquer aux objets ce qu'ils doivent faire et comment le faire par défaut. (Les méthodes par défaut dans les interfaces sont une nouvelle fonctionnalité ajoutée à Java 8.) En d'autres termes, une interface est un contrat que les classes d'implémentation doivent respecter..
Une interface est définie en utilisant le interface
mot clé en Kotlin (similaire à Java).
class Résultat class Interface étudiant StudentRepository fun getById (id: long): étudiant fun getResultsById (id: long): List
Dans le code ci-dessus, nous avons déclaré StudentRepository
interface. Cette interface contient deux méthodes abstraites: getById ()
et getResultsById ()
. Notez que, y compris le abstrait
le mot clé est redondant dans une méthode d'interface car ils sont déjà abstraites de manière implicite.
Une interface est inutile sans un ou plusieurs implémenteurs. Créons donc une classe qui implémentera cette interface..
class StudentLocalDataSource: StudentRepository annule fun getResults (id: Long): List// do implementation remplacez fun getById (id: Long): Étudiant // do implementation
Ici nous avons créé une classe StudentLocalDataSource
qui met en œuvre le StudentRepository
interface.
Nous utilisons le passer outre
modificateur pour étiqueter les méthodes et les propriétés que nous voulons redéfinir à partir de l’interface ou de la super-classe. @Passer outre
annotation en Java.
Notez les règles supplémentaires suivantes concernant les interfaces dans Kotlin:
passer outre
modificateur est obligatoire dans Kotlin, contrairement à Java. Voyons un exemple de méthode d'interface avec une implémentation par défaut.
interface StudentRepository //… fun delete (student: Student) // implémentation
Dans le code précédent, nous avons ajouté une nouvelle méthode effacer()
avec une implémentation par défaut (bien que je n'aie pas ajouté le code d'implémentation réel à des fins de démonstration).
Nous avons également la liberté de remplacer l'implémentation par défaut si nous voulons.
class StudentLocalDataSource: StudentRepository //… remplace fun delete (student: Student) // implémentation
Comme indiqué, une interface Kotlin peut avoir des propriétés, mais notez qu'elle ne peut pas maintenir l'état. (Cependant, n'oubliez pas que les classes abstraites peuvent conserver l'état.) Ainsi, la définition d'interface suivante avec une déclaration de propriété fonctionnera.
interface StudentRepository val propFoo: Boolean // fonctionnera // //
Mais si nous essayons d'ajouter un état à l'interface en attribuant une valeur à la propriété, cela ne fonctionnera pas.
interface StudentRepository val propFoo: Boolean = true // Erreur: les initialiseurs de propriétés ne sont pas autorisés dans les interfaces //…
Cependant, une propriété d'interface dans Kotlin peut avoir des méthodes getter et setter (bien que cette dernière option uniquement si la propriété est mutable). Notez également que la propriété dans une interface ne peut pas avoir un champ de sauvegarde.
interface StudentRepository var propFoo: Boolean get () = true set (valeur) if (valeur) // faire quelque chose //…
Nous pouvons également redéfinir une propriété d'interface si vous le souhaitez, afin de la redéfinir.
class StudentLocalDataSource: StudentRepository //… substitue var propFoo: Boolean get () = false set (valeur) if (valeur)
Regardons le cas où une classe implémente plusieurs interfaces avec la même signature de méthode. Comment la classe décide-t-elle quelle méthode d'interface appeler?
interface InterfaceA fun funD () interfaceB fun funD ()
Ici, nous avons deux interfaces qui ont une méthode avec la même signature fonds()
. Créons une classe qui implémente ces deux interfaces et remplace la fonds()
méthode.
class classA: InterfaceA, InterfaceB override fun funD () super.funD () // Erreur: de nombreux super-types disponibles, veuillez spécifier celui que vous voulez dire entre crochets, p. ex. 'super'
Le compilateur ne sait pas comment appeler le super.funD ()
méthode car les deux interfaces implémentées par la classe ont la même signature de méthode.
Pour résoudre ce problème, nous encapsulons le nom de l'interface pour laquelle nous voulons appeler la méthode entre crochets
. (IntelliJ IDEA ou Android Studio vous donneront un indice sur la façon de résoudre ce problème quand il se présentera.)
classe classA: InterfaceA, InterfaceB override fun funD () super.funD ()
Ici, nous allons appeler le fonds()
méthode de InterfaceA
. Problème résolu!
Une nouvelle classe (sous-classe) est créée en acquérant les membres d'une classe existante (superclasse) et éventuellement en redéfinissant leur implémentation par défaut. Ce mécanisme est appelé héritage en programmation orientée objet (OOP). Ce qui rend Kotlin si impressionnant, c’est qu’il englobe à la fois les paradigmes de programmation orientée objet et de programmation fonctionnelle, le tout dans un seul langage..
La classe de base pour toutes les classes de Kotlin est Tout
.
classe Personne: N'importe lequel
le Tout
le type est équivalent à Objet
type que nous avons en Java.
public open class Any opérateur public ouvert fun est égal à (autre: Any?): Booléen public open fun hashCode (): Int public ouvert fun toString (): String
le Tout
type contient les membres suivants: équivaut à()
, hashcode ()
, et aussi toString ()
méthodes (similaire à Java).
Nos classes n'ont pas besoin d'étendre explicitement ce type. Si vous ne spécifiez pas explicitement quelle classe une nouvelle classe étend, la classe s'étend Tout
implicitement. Pour cette raison, vous n'avez généralement pas besoin d'inclure : Tout
dans votre code, nous le faisons dans le code ci-dessus à des fins de démonstration.
Voyons maintenant comment créer des classes dans Kotlin en gardant à l'esprit l'héritage..
classe Student classe GraduateStudent: Student ()
Dans le code ci-dessus, le Étudiant diplomé
la classe étend la superclasse Étudiant
. Mais ce code ne compilera pas. Pourquoi? Parce que les classes et les méthodes sont final
par défaut dans Kotlin. En d'autres termes, elles ne peuvent pas être étendues par défaut, contrairement à Java où les classes et les méthodes sont ouvertes par défaut..
Les meilleures pratiques en matière de génie logiciel vous recommandent de commencer à créer vos classes et méthodes. final
par défaut, c'est-à-dire. si elles ne sont pas spécifiquement destinées à être redéfinies ou remplacées dans des sous-classes. L’équipe de Kotlin (JetBrains) a appliqué cette philosophie de codage et de nombreuses autres meilleures pratiques de développement pour développer ce langage moderne..
Pour permettre la création de sous-classes à partir d’une superclasse, nous devons explicitement marquer la superclasse avec le signe ouvrir
modificateur. Ce modificateur s'applique également à toute propriété ou méthode de superclasse qui doit être remplacée par des sous-classes..
classe ouverte étudiant
Nous mettons simplement le ouvrir
modificateur avant le classe
mot-clé. Nous avons maintenant demandé au compilateur de permettre à notre Étudiant
la classe doit être ouverte pour l'extension.
Comme indiqué précédemment, les membres d'une classe Kotlin sont également définitifs par défaut.
classe ouverte Student open fun schoolFees (): BigDecimal // do implementation
Dans le code précédent, nous avons marqué le frais de scolarité
fonctionne comme ouvrir
-afin que les sous-classes puissent le remplacer.
classe ouverte GraduateStudent: Student () remplace fun schoolFees (): BigDecimal return super.schoolFees () + CalculateSchoolFees () fun privé CalculateSchoolFees (): BigDecimal // calcule et retourne les frais de scolarité
Ici, l'ouvert frais de scolarité
fonction de la superclasse Étudiant
est remplacé par le Étudiant diplomé
classe en ajoutant le passer outre
modificateur avant le amusement
mot-clé. Notez que si vous substituez un membre d’une superclasse ou d’une interface, le membre substituant sera également ouvrir
Par défaut, comme dans l'exemple ci-dessous:
class ComputerScienceStudent: GraduateStudent () substitue fun schoolFees (): BigDecimal return super.schoolFees () + CalculateSchoolFess () fun privé CalculateSchoolFess (): BigDecimal // calcule et retourne les frais de scolarité
Même si nous n'avons pas marqué le frais de scolarité()
méthode dans le Étudiant diplomé
classe avec le ouvrir
modificateur, nous pouvons toujours le remplacer-comme nous l'avons fait dans le ComputerScienceStudent
classe. Pour que cela soit évité, nous devons marquer le membre dominant comme final
.
N'oubliez pas que nous pouvons ajouter de nouvelles fonctionnalités à une classe, même si celle-ci est définitive, en utilisant des fonctions d'extension dans Kotlin. Pour un rappel sur les fonctions d'extension, consultez mes fonctions avancées dans la publication Kotlin. De plus, si vous avez besoin d’un rappel sur la façon de donner même à une classe finale de nouvelles propriétés sans en hériter, lisez la section sur les propriétés d’extension dans la section Mes propriétés et classes avancées..
Si notre super-classe a un constructeur primaire comme celui-ci:
classe ouverte Student (val firstName: String, val lastName: String) //…
Ensuite, toute sous-classe doit appeler le constructeur principal de la superclasse.
classe ouverte GraduateStudent (prénom: chaîne, nom de famille: chaîne): étudiant (prénom, nom de famille) //…
Nous pouvons simplement créer un objet du Étudiant diplomé
classe comme d'habitude:
val graduStudent = GraduateStudent ("Jon", "Snow") println (graduStudent.firstName) // Jon
Si la sous-classe veut appeler le constructeur de la super-classe à partir de son constructeur secondaire, nous utilisons le super
mot-clé (similaire à la façon dont les constructeurs de super-classes sont appelés en Java).
classe ouverte GraduateStudent: Student //… thèse privée privée: String = "" constructeur (prénom: String, nom: String, thèse: String): super (prénom, nom) this.thesis = thèse
Si vous avez besoin d'un rappel sur les constructeurs de classes à Kotlin, veuillez visiter mon post Classes and Objects.
Une autre bonne chose à faire à Kotlin est de donner à un type un alias.
Voyons un exemple.
Classe de données Person (val firstName: String, val lastName: String, val age: Int)
Dans la classe ci-dessus, nous pouvons assigner le Chaîne
et Int
types pour le La personne
alias de propriétés à l'aide du typealias
modificateur à Kotlin. Ce modificateur est utilisé pour créer un alias de n'importe quel type dans Kotlin, y compris ceux que vous avez créés..
typealias Nom = Chaîne typealias Age = Int Classe de données Personne (val firstName: Name, val lastName: Nom, val age: Age)
Comme vous pouvez le constater, nous avons créé un alias prénom
et Âge
pour les deux Chaîne
et Int
types respectivement. Nous avons maintenant remplacé le Prénom
et nom de famille
type de propriété à notre alias prénom
-et aussi Int
taper à Âge
alias. Notez que nous n’avons créé aucun nouveau type. Nous avons plutôt créé un alias pour les types..
Celles-ci peuvent être pratiques lorsque vous souhaitez fournir une meilleure signification ou sémantique aux types de votre base de code Kotlin. Alors utilisez-les judicieusement!
Dans ce tutoriel, vous en avez appris plus sur la programmation orientée objet de Kotlin. Nous avons couvert les points suivants:
Si vous avez appris Kotlin à travers notre série Kotlin From Scratch, assurez-vous d’avoir tapé le code que vous voyez et de l’avoir exécuté sur votre IDE. Un bon conseil pour bien comprendre un nouveau langage de programmation (ou tout concept de programmation) que vous apprenez est de vous assurer de ne pas simplement lire la ressource pédagogique ou le guide, mais également de saisir le code et de l'exécuter.!
Dans le prochain tutoriel de la série Kotlin From Scratch, vous découvrirez la gestion des exceptions dans Kotlin. À bientôt!
Pour en savoir plus sur la langue Kotlin, je vous recommande de consulter la documentation Kotlin. Ou consultez certains de nos autres articles sur le développement d'applications Android ici sur Envato Tuts!