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 avez appris sur les classes et les objets dans Kotlin. Dans ce didacticiel, nous allons continuer à en apprendre davantage sur les propriétés et également à examiner les types avancés de classes dans Kotlin en explorant les éléments suivants:
Nous pouvons déclarer une propriété non nulle dans Kotlin comme initialisé tardivement. Cela signifie qu'une propriété non NULL ne sera pas initialisée au moment de la déclaration avec une initialisation valeur réelle qui ne se produira pas via un constructeur, mais qu'elle sera initialisée tardivement par une méthode ou une injection de dépendance..
Regardons un exemple pour comprendre ce modificateur de propriété unique.
class Presenter dépôt privé var: référentiel? = null fun initRepository (référentiel: référentiel): Unit this.repository = repo class Repository fun saveAmount (amount: Double)
Dans le code ci-dessus, nous avons déclaré un mutable nullable dépôt
propriété qui est de type Dépôt
-à l'intérieur de la classe Présentateur
-et nous avons ensuite initialisé cette propriété à null pendant la déclaration. Nous avons une méthode initRepository ()
dans le Présentateur
classe qui réinitialise cette propriété plus tard avec un réel Dépôt
exemple. Notez que vous pouvez également affecter une valeur à cette propriété à l'aide d'un injecteur de dépendance tel que Dagger..
Maintenant, invoquons des méthodes ou des propriétés sur cette dépôt
propriété, nous devons faire une vérification nulle ou utiliser l'opérateur d'appel sécurisé. Pourquoi? Parce que le dépôt
propriété est de type nullable (Dépôt?
). (Si vous avez besoin d'un rappel sur l'annulation de la nullité dans Kotlin, veuillez visiter Nullability, Loops et Conditions).
// Dans la classe Presenter fun save (montant: double) référentiel? .SaveAmount (montant)
Pour éviter de devoir effectuer des vérifications nulles chaque fois que nous devons appeler la méthode d'une propriété, nous pouvons marquer cette propriété avec le symbole en retard
modificateur-cela signifie que nous avons déclaré cette propriété (qui est une instance d'une autre classe) comme initialisé tardivement (signifiant que la propriété sera initialisée plus tard).
class Presenter dépôt tardif privé private late: Repository //…
Désormais, tant que nous attendons qu'une valeur soit attribuée à la propriété, nous pouvons accéder aux méthodes de la propriété sans effectuer de contrôle null. L'initialisation de la propriété peut se produire soit dans une méthode setter, soit par injection de dépendance.
repository.saveAmount (montant)
Notez que si nous essayons d’accéder aux méthodes de la propriété avant son initialisation, nous obtiendrons un kotlin.UninitializedPropertyAccessException
au lieu d'une NullPointerException
. Dans ce cas, le message d'exception sera "le référentiel de propriété Lateinit n'a pas été initialisé".
Notez également les restrictions suivantes lors du retard d’initialisation d’une propriété avec en retard
:
var
).Int
, Double
, Flotte
, etc. Dans Advanced Functions, j’ai introduit le en ligne
modificateur pour les fonctions d'ordre supérieur - ceci permet d'optimiser les fonctions d'ordre supérieur qui acceptent un lambda en tant que paramètre.
À Kotlin, nous pouvons également utiliser cette en ligne
modificateur sur les propriétés. L'utilisation de ce modificateur optimisera l'accès à la propriété.
Voyons un exemple pratique.
classe Student val nickName: String get () println ("Nom de Nick récupéré") retourne "koloCoder" fun main (args: Array) val student = Student () print (student.nickName)
Dans le code ci-dessus, nous avons une propriété normale, surnom
, ça n'a pas le en ligne
modificateur. Si nous décompilons l’extrait de code, utilisez la commande Afficher le bytecode de Kotlin fonction (si vous utilisez IntelliJ IDEA ou Android Studio, utilisez Outils > Kotlin > Afficher le bytecode de Kotlin), nous verrons le code Java suivant:
public final class Student @NotNull public final String getNickName () String var1 = "Pseudo récupéré"; System.out.println (var1); retourne "koloCoder"; public final class InlineFunctionKt public final final statique principal (@NotNull String [] args) Intrinsics.checkParameterIsNotNull (args, "args"); Étudiant étudiant = nouvel étudiant (); String var2 = student.getNickName (); System.out.print (var2);
Dans le code Java généré ci-dessus (certains éléments du code généré ont été supprimés pour des raisons de brièveté), vous pouvez voir que principale()
méthode le compilateur a créé un Étudiant
objet, appelé le getNickName ()
méthode, puis imprimé sa valeur de retour.
Spécifions maintenant la propriété comme en ligne
à la place, et comparez le bytecode généré.
//… inline val nickName: String //…
Nous venons d'insérer le en ligne
modificateur avant le modificateur de variable: var
ou val
. Voici le bytecode généré pour cette propriété inline:
//… public final final statique principal (@NotNull String [] args) Intrinsics.checkParameterIsNotNull (args, "args"); Étudiant étudiant = nouvel étudiant (); String var3 = "Pseudo récupéré"; System.out.println (var3); String var2 = "koloCoder"; System.out.print (var2); //…
Encore une fois, du code a été supprimé, mais l’essentiel à noter est le principale()
méthode. Le compilateur a copié la propriété obtenir()
corps de la fonction et collé dans le site d'appel (ce mécanisme est similaire aux fonctions inline).
Notre code a été optimisé car il n'est pas nécessaire de créer un objet et d'appeler la méthode property getter. Mais, comme discuté dans les fonctions inline post, nous aurions un plus gros bytecode qu’avant, alors utilisez-le avec prudence.
Notez également que ce mécanisme fonctionnera pour les propriétés qui n'ont pas de champ de sauvegarde (rappelez-vous qu'un champ de sauvegarde est simplement un champ utilisé par les propriétés lorsque vous souhaitez modifier ou utiliser ces données de champ)..
Dans Advanced Functions, j'ai également abordé les fonctions d'extension. Celles-ci nous permettent d'étendre une classe avec de nouvelles fonctionnalités sans avoir à hériter de cette classe. Kotlin fournit également un mécanisme similaire pour les propriétés, appelé propriétés d'extension.
val String.upperCaseFirstLetter: String get () = this.substring (0, 1) .toUpperCase (). plus (this.substring (1))
Dans le post Fonctions avancées, nous avons défini un uppercaseFirstLetter ()
fonction d'extension avec type de récepteur Chaîne
. Ici, nous l'avons converti en une propriété d'extension de premier niveau. Notez que vous devez définir une méthode de lecture sur votre propriété pour que cela fonctionne..
Donc, avec ces nouvelles connaissances sur les propriétés d'extension, vous saurez que si vous avez toujours souhaité qu'une classe ait une propriété qui n'était pas disponible, vous êtes libre de créer une propriété d'extension de cette classe..
Commençons par une classe Java typique ou POJO (Plain Old Java Object).
classe publique BlogPost private final String title; URL finale de l'URI privée; description finale privée de la chaîne; private final Date publishDate; //… constructeur non inclus par souci de brièveté @Override public boolean égal à (Object o) if (this == o) return true; if (o == null || getClass ()! = o.getClass ()) renvoie false; BlogPost blogPost = (BlogPost) o; if (title! = null?! title.equals (blogPost.title): blogPost.title! = null) return false; if (url! = null?! url.equals (blogPost.url): blogPost.url! = null) return false; if (description! = null?! description.equals (blogPost.description): blogPost.description! = null) return false; return publishDate! = null? publishDate.equals (blogPost.publishDate): blogPost.publishDate == null; @Override public int hashCode () int result = title! = Null? title.hashCode (): 0; result = 31 * result + (url! = null? url.hashCode (): 0); result = 31 * result + (description! = null? description.hashCode (): 0); result = 31 * result + (publishDate! = null? publishDate.hashCode (): 0); retourne le résultat; @Override public String toString () return "BlogPost " + "title = '" + title +' \ "+", url = "+ url +", + description + "\" + ", publishDate =" + publishDate + ''; //… les setters et getters ont également été ignorés pour des raisons de brièveté
Comme vous pouvez le constater, nous devons coder explicitement les accesseurs de propriété de classe: le getter et le setter, ainsi que hashcode
, équivaut à
, et toString
méthodes (même si IntelliJ IDEA, Android Studio ou la bibliothèque AutoValue peuvent nous aider à les générer). Nous voyons ce type de code passe-partout dans la couche de données d'un projet Java typique. (J'ai enlevé les accesseurs de champ et le constructeur par souci de brièveté).
Ce qui est bien, c’est que l’équipe Kotlin nous a fourni le Les données
modificateur pour les classes éliminant l'écriture.
Écrivons maintenant le code précédent dans Kotlin à la place.
classe de données BlogPost (titre var: String, URL var: URI, description var: String, var publishDate: Date)
Impressionnant! Nous spécifions simplement le Les données
modificateur avant le classe
mot-clé pour créer une classe de données, comme ce que nous avons fait dans notre BlogPost
Kotlin classe ci-dessus. Maintenant le équivaut à
, hashcode
, toString
, copie
, et des méthodes à composants multiples seront créées sous le capot pour nous. Notez qu'une classe de données peut étendre d'autres classes (ceci est une nouvelle fonctionnalité de Kotlin 1.1).
équivaut à
MéthodeCette méthode compare l'égalité des objets entre deux objets et renvoie true s'ils sont égaux ou false sinon. En d'autres termes, il compare si les deux instances de la classe contiennent les mêmes données.
student.equals (student3) // utilisation du == dans Kotlin student == student3 // identique à l’utilisation de equals ()
En Kotlin, en utilisant l'opérateur d'égalité ==
appellera le équivaut à
méthode dans les coulisses.
hashCode
Méthode Cette méthode retourne une valeur entière utilisée pour le stockage et la récupération rapides des données stockées dans une structure de données de collecte basée sur un hachage, par exemple dans le répertoire. HashMap
et HashSet
types de collection.
toString
MéthodeCette méthode retourne un Chaîne
représentation d'un objet.
Classe de données Person (var firstName: String, var lastName: String) val person = Person ("Chike", "Mgbemena") println (personne) // affiche "Person (firstName = Chike, lastName = Mgbemena)"
En appelant simplement l'instance de la classe, nous obtenons un objet de chaîne renvoyé à nous. Kotlin appelle l'objet. toString ()
sous le capot pour nous. Mais si on ne met pas le Les données
mot-clé in, voyez ce que notre représentation de chaîne d'objet serait:
com.chike.kotlin.classes.Person@2f0e140b
Beaucoup moins informatif!
copie
MéthodeCette méthode nous permet de créer une nouvelle instance d'un objet avec toutes les mêmes valeurs de propriété. En d'autres termes, il crée une copie de l'objet.
val person1 = Person ("Chike", "Mgbemena") println (person1) // Person (prénom = Chike, lastName = Mgbemena) val person2 = person1.copy () println (person2) // personne (prénom = Chike, lastName = Mgbemena)
Une bonne chose à propos du copie
méthode en Kotlin est la possibilité de changer les propriétés pendant la copie.
val person3 = person1.copy (lastName = "Onu") println (person3) // Person3 (firstName = Chike, lastName = Onu)
Si vous êtes un codeur Java, cette méthode est similaire à la cloner()
méthode que vous connaissez déjà. Mais le Kotlin copie
méthode a des fonctionnalités plus puissantes.
dans le La personne
classe, nous avons également deux méthodes générées automatiquement pour nous par le compilateur en raison de la Les données
mot clé placé dans la classe. Ces deux méthodes sont préfixées par "composant", puis suivies d'un suffixe numérique: composant1 ()
, composant2 ()
. Chacune de ces méthodes représente les propriétés individuelles du type. Notez que le suffixe correspond à l'ordre des propriétés déclarées dans le constructeur principal.
Donc, dans notre exemple d'appel composant1 ()
retournera le prénom, et en appelant composant2 ()
renverra le nom de famille.
println (person3.component1 ()) // Chike println (person3.component2 ()) // Onu
L'appel des propriétés à l'aide de ce style est difficile à comprendre et à lire. Il est donc préférable d'appeler explicitement le nom de la propriété. Cependant, ces propriétés créées implicitement ont un objectif très utile: elles nous permettent de faire une déclaration de déstructuration dans laquelle nous pouvons affecter chaque composant à une variable locale..
val (prenom, prenom) = personne ("Angelina", "Jolie") println (prenom + "" + nom) // Angelina Jolie
Ce que nous avons fait ici est d’affecter directement les première et deuxième propriétés (Prénom
et nom de famille
) du La personne
taper aux variables Prénom
et nom de famille
respectivement. J'ai aussi discuté de ce mécanisme appelé déclaration de déstructuration dans la dernière section de la publication Packages and Basic Functions.
Dans l'article Plus de plaisir avec les fonctions, je vous ai dit que Kotlin prend en charge les fonctions locales ou imbriquées, une fonction déclarée dans une autre fonction. De même, Kotlin prend également en charge les classes imbriquées, une classe créée dans une autre classe..
classe OuterClass classe NestedClass fun nestedClassFunc ()
Nous appelons même les fonctions publiques de la classe imbriquée, comme on le voit ci-dessous: une classe imbriquée dans Kotlin équivaut à statique
classe imbriquée en Java. Notez que les classes imbriquées ne peuvent pas stocker une référence à leur classe externe.
val nestedClass = OuterClass.NestedClass () nestedClass.nestedClassFunc ()
Nous sommes également libres de définir la classe imbriquée comme privée. Cela signifie que nous ne pouvons créer qu'une instance du NestedClass
dans le cadre de la OuterClass
.
Les classes internes, en revanche, peuvent référencer la classe externe dans laquelle elle a été déclarée. Pour créer une classe interne, nous plaçons le interne
mot clé avant le classe
mot clé dans une classe imbriquée.
class OuterClass () val oCPropt: String = "Yo" classe intérieure InnerClass fun innerClassFunc () val outerClass = this @ OuterClass print (outerClass.oCPropt) // affiche "Yo"
Ici nous référons le OuterClass
du InnerClass
en utilisant ceci @ OuterClass
.
Un type enum déclare un ensemble de constantes représentées par des identificateurs. Ce type spécial de classe est créé par le mot clé enum
qui est spécifié avant la classe
mot-clé.
enum class Country NIGERIA, GHANA, CANADA
Pour récupérer une valeur enum basée sur son nom (comme en Java), procédez comme suit:
Country.valueOf ("NIGERIA")
Ou nous pouvons utiliser le Kotlin enumValueOf
méthode d'assistance pour accéder aux constantes de manière générique:
enumValueOf("NIGERIA")
De plus, nous pouvons obtenir toutes les valeurs (comme pour une énumération Java) comme ceci:
Pays.valeurs ()
Enfin, nous pouvons utiliser le Kotlin enumValues
méthode d'assistance pour obtenir toutes les entrées enum de manière générique:
enumValues()
Ceci retourne un tableau contenant les entrées enum.
Tout comme une classe normale, le enum
type peut avoir son propre constructeur avec des propriétés associées à chaque constante enum.
enum class Country (code appelant val: Int) NIGERIA (234), USA (1), GHANA (233)
dans le Pays
constructeur primaire de type enum, nous avons défini la propriété immuable appelantCodes
pour chaque constante enum. Dans chacune des constantes, nous avons passé un argument au constructeur.
Nous pouvons alors accéder à la propriété constants comme ceci:
val pays = pays.NIGERIA print (country.callingCode) // 234
Une classe scellée dans Kotlin est une classe abstraite (vous ne souhaitez jamais en créer d'objets) que d'autres classes peuvent étendre. Ces sous-classes sont définies dans le corps de la classe scellée du même fichier. Toutes ces sous-classes étant définies à l'intérieur du corps de classe scellé, nous pouvons connaître toutes les sous-classes possibles en visualisant simplement le fichier..
Voyons un exemple pratique.
// shape.kt classe scellée Classe de forme Cercle: Classe de forme () Triangle: Classe de forme () Rectangle: Forme ()
Pour déclarer une classe comme scellée, nous insérons le scellé
modificateur avant le classe
modificateur dans la déclaration de classe en-tête-dans notre cas, nous avons déclaré le Forme
classe comme scellé
. Une classe scellée est incomplète sans ses sous-classes, tout comme une classe abstraite typique. Nous devons donc déclarer les sous-classes individuelles dans le même fichier (forme.kt dans ce cas). Notez que vous ne pouvez pas définir une sous-classe d'une classe scellée à partir d'un autre fichier..
Dans notre code ci-dessus, nous avons spécifié que le Forme
la classe ne peut être prolongée que par les classes Cercle
, Triangle
, et Rectangle
.
Les classes scellées à Kotlin ont les règles supplémentaires suivantes:
abstrait
à une classe scellée, mais cela est redondant car les classes scellées sont abstraites par défaut.ouvrir
ou final
modificateur. Les classes qui étendent des sous-classes d'une classe scellée peuvent être placées dans le même fichier ou dans un autre fichier. La sous-classe de classe scellée doit être marquée avec le ouvrir
modificateur (vous en apprendrez plus sur l'héritage à Kotlin dans le prochain article).
// employee.kt sealed classe Employee open class Artiste: Employee () // musician.kt class Musicien: Artiste ()
Une classe scellée et ses sous-classes sont vraiment pratiques dans un quand
expression. Par exemple:
fun whatIsIt (shape: Shape) = quand (shape) est Circle -> println ("Un cercle") est Triangle -> println ("Un triangle") est Rectangle -> println ("Un rectangle")
Ici, le compilateur est intelligent pour assurer que nous avons couvert tous les possibles quand
cas. Cela signifie qu'il n'est pas nécessaire d'ajouter le autre
clause.
Si nous devions plutôt procéder comme suit:
fun whatIsIt (shape: Shape) = quand (shape) est Circle -> println ("Un cercle") est Triangle -> println ("Un triangle")
Le code ne compilerait pas car nous n'avons pas inclus tous les cas possibles. Nous aurions l'erreur suivante:
Kotlin: à la place, l'expression 'quand' doit être exhaustive, ajouter plutôt que 'est une branche' rectangle 'ou une branche' else '.
Donc, nous pourrions soit inclure le est rectangle
cas ou inclure le autre
clause pour compléter le quand
expression.
Dans ce tutoriel, vous en avez appris plus sur les cours de Kotlin. Nous avons couvert les éléments suivants concernant les propriétés de classe:
En outre, vous avez découvert certaines classes intéressantes et avancées telles que les classes data, enum, imbriquées et scellées. Dans le prochain didacticiel de la série Kotlin From Scratch, vous découvrirez les interfaces et l'héritage 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!