Définition des classes
En Kotlin, le mot-clé class permet de déclarer une classe. Une classe peut regrouper des propriétés, des méthodes, des constructeurs et des classes imbriquées.
class ProfilUtilisateur {
var pseudo: String = "Anonyme"
var niveau: Int = 1
fun afficherInfos() {
println("Joueur : $pseudo, Niveau : $niveau")
}
}
Si une classe ne contient aucun corps (pas de propriétés ni de méthodes), les acoclades peuvent être omises : class ClasseVide.
Instanciation d'objets
Pour créer une instance, on appelle le constructeur comme une fonction classique (il n'y a pas de mot-clé new) :
val profil = ProfilUtilisateur()
profil.pseudo = "KotlinDev"
profil.niveau = 10
Constructeurs et Initialisasion
Kotlin distingue le constructeur primaire des constructeurs secondaires.
Constructeur primaire
Il est déclaré directement dans l'en-tête de la classe :
class Appareil(val marque: String, var prix: Double)
Bloc d'initialisation
Le mot-clé init permet d'exécuter de la logique lors de la création de l'objet, car le constructeur primaire ne peut pas contenir de code complexe.
class Appareil(val marque: String, var prix: Double) {
init {
println("Appareil de marque $marque enregistré avec un prix de $prix €")
}
}
Constructeurs secondaires
Une classe peut définir des constructeurs additionnels via le mot-clé constructor. Si un constructeur primaire existe, chaque constructeur secondaire doit le déléguer.
class Dimension(val largeur: Int, val hauteur: Int) {
// Délégation au constructeur primaire
constructor(cote: Int) : this(cote, cote)
}
Héritage et Polymorphisme
Par défaut, toutes les classes en Kotlin sont final (non héritables). Pour autoriser l'héritage, utilisez le mot-clé open.
open class Vehicule {
open fun klaxonner() {
println("Bip bip !")
}
}
class Moto : Vehicule() {
override fun klaxonner() {
println("Vroum vroum !")
}
}
Classes Abstraites
Une classe abstraite ne peut pas être instanciée directement. Elle sert de modèle pour d'autres classes.
abstract class Instrument(val nom: String) {
abstract fun jouer()
}
class Piano : Instrument("Piano") {
override fun jouer() {
println("Le piano joue une mélodie.")
}
}
Classes Imbriquées et Internes
Une classe définie à l'intérieur d'une autre est "imbriquée" par défaut (elle n'accède pas aux membres de la classe parente).
class Externe {
private val message = "Secret"
class Imbriquee {
fun test() = "Accès impossible au secret"
}
inner class Interne {
fun lireSecret() = message // Accès possible via 'inner'
}
}
Classes de Données (Data Classes)
Utilisées principalement pour stocker des données, elles génèrent automatiquement equals(), hashCode(), toString() et copy().
data class Livre(val titre: String, val auteur: String)
Classes Scellées (Sealed Classes)
Les classes scellées permettent de restreindre la hiérarchie d'héritage. Elles sont idéales pour représenter des états dans une application.
sealed class EtatReseau
class Succes(val code: Int) : EtatReseau()
class Erreur(val message: String) : EtatReseau()
object Chargement : EtatReseau()
Interfaces
Les interfaces définissent un contrat. Contrairement à Java 7, elles peuvent contenir des implémentations par défaut pour les méthodes.
interface Actionnable {
val id: String
fun executer()
fun log() {
println("Action $id en cours...")
}
}
class Commande(override val id: String) : Actionnable {
override fun executer() {
println("Exécution de la commande.")
}
}
Objets et Singletons
Le mot-clé object permet de définir un singleton (une instance unique).
object GestionnaireConfiguration {
var theme: String = "Sombre"
}
// Utilisation : GestionnaireConfiguration.theme
Compagnons (Companion Objects)
Le companion object remplace les membres statiques de Java. Il est lié à la classe plutôt qu'à une instance.
class FabriqueCafe {
companion object {
fun preparerExpresso() = "Expresso prêt !"
}
}
// Appel direct via la classe
val cafe = FabriqueCafe.preparerExpresso()
Ils peuvent également implémenter des interfaces, ce qui les rend puissants pour le pattern "Factory" :
interface Usine<T> {
fun creer(): T
}
class Robot {
companion object : Usine<Robot> {
override fun creer(): Robot = Robot()
}
}