cursus.

Cours 1 · Du procédural à l'objetLeçon 2 sur 2

Classes et objets

5 h de lecture9 sections Version PDF

À la fin de cette leçon, vous saurez

La classe comme moule et l'objet comme instance ; attributs, méthodes, constructeur, référence this, création par new, cycle de vie d'un objet.

Compte a = new Compte(100);Compte b = new Compte(50);a.deposer(30);System.out.println(b.getSolde());     /* 50, pas 80 */

Cette évidence n'en est pas une au premier contact. La question « mais alors, il y a deux soldes ? » revient chaque année, et elle est légitime : le code de deposer est écrit une seule fois, et l'on peine à voir comment une seule ligne peut modifier une case sans toucher à l'autre.

C'est le premier point qui coince du semestre. Il se règle d'une seule façon : en regardant plusieurs objets côte à côte, pas à pas.

Le moule et la gaufre

Une classe décrit ce qu'un objet contiendra et ce qu'il saura faire. Elle n'existe qu'en un exemplaire, et elle ne contient aucune donnée d'utilisateur — c'est un moule.

Un objet, ou instance, est une chose fabriquée avec ce moule. Il possède ses propres attributs, distincts de ceux de tous les autres objets de la même classe.

L'analogie tient si l'on ne l'étire pas : le moule à gaufres ne contient pas de pâte, et deux gaufres issues du même moule ont la même forme et des garnitures différentes.

public class Compte {    private double solde;              // attribut : une case PAR objet    private String titulaire;     public Compte(String titulaire, double depotInitial) {   // constructeur        this.titulaire = titulaire;        this.solde = depotInitial;    }     public void deposer(double montant) {                    // méthode        this.solde += montant;    }     public double getSolde() {        return this.solde;    }}

Trois vocabulaires à fixer. Les attributs — ou champs — sont les variables déclarées dans la classe : chaque objet en reçoit un jeu complet. Les méthodes sont les fonctions déclarées dans la classe : elles existent une seule fois en mémoire, et reçoivent l'objet sur lequel elles travaillent. Le constructeur est la méthode particulière appelée à la création.

Une différence avec le C mérite d'être signalée tout de suite : en Java, les attributs sont initialisés automatiquement — 0 pour les nombres, false pour les booléens, null pour les références. Ce n'est pas le cas des variables locales, qui restent non initialisées comme au chapitre 2 du cours de programmation, et le compilateur refuse de les lire.

Le constructeur

public Compte(String titulaire, double depotInitial) { ... }

Trois règles, et la troisième surprend.

Il porte exactement le nom de la classe, majuscule comprise. Il n'a aucun type de retour, pas même void — écrire void Compte(...) en fait une méthode ordinaire nommée Compte, qui compile et n'est jamais appelée par new. C'est une erreur classique, et elle est silencieuse.

Il sert à établir l'invariant de l'objet : à la sortie du constructeur, l'objet doit être dans un état valide. Un compte sans titulaire ou avec un solde négatif ne doit pas pouvoir exister — et c'est le constructeur qui l'empêche, comme le chapitre 3 le formalisera.

Enfin, une règle de Java qu'il vaut mieux connaître : si l'on n'écrit aucun constructeur, le compilateur en fournit un par défaut, sans paramètre. Dès qu'on en écrit un seul, ce constructeur par défaut disparaît — et new Compte() cesse de compiler. Il faut alors le réécrire si on en veut un.

Ce que fait new

L'instruction Compte a = new Compte("Ana", 100); fait quatre choses, dans cet ordre.

1. ALLOUER   un objet sur le TAS, avec une case par attribut2. INITIALISER  ces cases aux valeurs par défaut (0, false, null)3. EXÉCUTER  le constructeur, qui les remplit vraiment4. RENDRE    une RÉFÉRENCE vers cet objet, qui est rangée dans a

Le mot important est le dernier. a ne contient pas l'objet, mais une référence vers lui — c'est-à-dire, en pratique, une adresse au sens du chapitre 7 du cours de programmation. L'objet vit sur le tas, la variable a vit sur la pile.

D'où une conséquence que le chapitre 4 exploitera :

Compte a = new Compte("Ana", 100);Compte b = a;                          // COPIE LA RÉFÉRENCE, pas l'objetb.deposer(50);a.getSolde();                          // 150 : c'est le MÊME objet

Il n'y a ici qu'un seul compte, désigné par deux noms. C'est exactement le passage par adresse du cours de programmation, et c'est ce qui distingue Java du C sur ce point : en Java, tout objet est manipulé par référence, sans qu'aucune étoile ne l'écrive.

this

Animation · étape 1 / 80:00 / 0:12

La classe est un MOULE : elle décrit ce qu'un compte contiendra, sans qu'aucun compte existe. Une seule chose existe déjà, la variable de classe `nombre` — elle appartient à la classe, pas à un objet, et il n'y en aura jamais qu'un exemplaire.

Prêt à lancer · 0:00 / 0:12
Étapes

this désigne l'objet sur lequel la méthode s'exécute. Il n'a de sens qu'à l'intérieur d'une méthode d'instance, et il change à chaque appel — c'est ce que l'animation montre.

Trois usages, du plus fréquent au plus rare.

Lever une ambiguïté. Quand un paramètre porte le même nom qu'un attribut, solde désigne le paramètre — le plus proche — et this.solde l'attribut. C'est le cas du constructeur ci-dessus, et c'est l'usage qu'on rencontre partout. Certains l'évitent en nommant les paramètres différemment ; l'écrasante majorité des codes Java fait l'inverse et emploie this.

Se passer soi-même à une autre méthode : journal.enregistrer(this).

Enchaîner les constructeurs : this(titulaire, 0) appelle un autre constructeur de la même classe, ce qui évite de dupliquer l'initialisation. L'appel doit être la première instruction.

Le contre-emploi à connaître : dans une méthode statique, this n'existe pas — il n'y a aucun objet courant. C'est le sujet du chapitre 4, et l'erreur non-static variable this cannot be referenced from a static context est celle que tout étudiant rencontre en écrivant son premier main.

Quiz · vérifiez votre compréhension Sans réponse

Après Compte a = new Compte(100); Compte b = a; b.deposer(50); que vaut a.getSolde() ?

Cycle de vie

Un objet naît avec new, vit tant qu'une référence le désigne, et meurt quand plus aucune ne le désigne.

Compte a = new Compte("Ana", 100);a = new Compte("Bo", 50);              // le premier compte n'est plus atteignable

Le premier objet existe toujours en mémoire, mais plus personne ne peut l'atteindre : c'est exactement la définition de la fuite du chapitre 8 du cours de programmation. La différence est que Java dispose d'un ramasse-miettes (garbage collector), qui repère périodiquement les objets inatteignables et récupère leur mémoire.

Trois conséquences pratiques, et la dernière est une mise en garde.

Il n'y a pas de free, ni de destructeur à écrire. La question « qui libère ? », qui occupait tout le chapitre 8 du C, ne se pose plus.

Le prix est un coût à l'exécution : le ramasse-miettes s'exécute quand il le décide, et peut introduire de brèves pauses. C'est acceptable presque partout, et rédhibitoire en temps réel dur — au sens du chapitre 1 du cours de systèmes.

Enfin, le ramasse-miettes ne supprime pas les fuites, il supprime une de leurs causes. Un objet encore référencé par une liste qu'on a oublié de vider ne sera jamais récupéré. La fuite en Java n'est pas « j'ai oublié de libérer » mais « je garde une référence dont je n'ai plus besoin » — plus subtile, et plus difficile à voir.

Quiz · vérifiez votre compréhension Sans réponse

Un étudiant écrit public void Compte(String nom) puis appelle new Compte(« Ana »), et le code ne compile pas. Pourquoi ?

À vous

L'exercice met deux objets côte à côte et affiche leur état après chaque instruction — c'est l'animation, mais que vous pilotez.

Quatre temps. Créer deux comptes et vérifier qu'un dépôt sur l'un ne touche pas l'autre. Écrire un constructeur qui valide son paramètre, avant même le chapitre 3. Faire l'expérience de l'alias : b = a, un dépôt, et les deux soldes. Enfin, deux pièges de this — un attribut masqué par un paramètre quand on oublie this, et une méthode détachée de son objet, qui montre que this n'est pas fixé une fois pour toutes.

Exercice · JavaScript · à vous de jouer

Mettez deux objets côte à côte, validez dans le constructeur, puis faites tomber les deux pièges de this.

En attente
// JavaScript possède class, constructor et this : la transposition depuis
// Java est directe, à la déclaration des types près.

class Compte {
  constructor(titulaire, depotInitial) {
    // ← à écrire : refuser un dépôt initial négatif, puis initialiser
    this.titulaire = titulaire;
    this.solde = depotInitial;
  }
  deposer(montant) { this.solde += montant; }
  getSolde() { return this.solde; }
  toString() { return this.titulaire + " : " + this.solde.toFixed(2); }
}

// Affiche l'état de plusieurs objets CÔTE À CÔTE, comme au tableau.
function etat(etiquette, ...comptes) {
  console.log("   " + etiquette.padEnd(28) +
    comptes.map((c) => c.toString()).join("   |   "));
}

// ── 1. Deux objets, deux jeux d'attributs ─────────────────────────────────
const a = new Compte("Ana", 100);
const b = new Compte("Bo", 50);
etat("après les deux new", a, b);
a.deposer(30);
etat("après a.deposer(30)", a, b);

// ── 2. L'alias ────────────────────────────────────────────────────────────
const c = a;               // COPIE LA RÉFÉRENCE, pas l'objet
c.deposer(20);
etat("après c.deposer(20)", a, b);
console.log("   a et c sont le même objet :", a === c);

// ── 3. L'attribut masqué ──────────────────────────────────────────────────
class CompteFautif {
  constructor(titulaire, solde) {
    titulaire = titulaire;   // ← sans this : on affecte le paramètre à lui-même
    solde = solde;
  }
  toString() { return this.titulaire + " : " + this.solde; }
}

// ── À VOUS ────────────────────────────────────────────────────────────────
// 1. Faites refuser un dépôt initial négatif par le constructeur.
// 2. Créez un CompteFautif et affichez-le : que valent ses attributs, et
//    pourquoi le code compile-t-il sans rien dire ?
// 3. Détachez la méthode : const f = a.deposer; f(10). Que se passe-t-il,
//    et qu'est-ce que cela apprend sur this ?

Console de sortie
Le résultat s'affiche dans la console

En travaux pratiques

Travaux pratiques 2 · sur machine

Le premier point qui coince : this

Faire disparaître la confusion entre la classe et l'objet, et entre le paramètre et le champ — en provoquant les deux erreurs plutôt qu'en les évitant.

3 h
Avant de commencer
  • Le TP 1
  1. 1. Deux objets

    Créez deux Document et modifiez le titre du premier. Affichez les deux. Puis affichez ce que vaut une variable statique modifiée sur l'un des deux.

  2. 2. Le constructeur qui ne fait rien

    Écrivez un constructeur dont les paramètres portent le même nom que les champs, SANS écrire this. Créez un objet et affichez ses champs. Expliquez.

  3. 3. Le réparer, deux fois

    Corrigez d'abord en renommant les paramètres, puis avec this. Dites laquelle des deux formes vous garderez et pourquoi.

  4. 4. this dans une méthode

    Écrivez une méthode qui renvoie l'objet lui-même, et enchaînez trois appels sur une seule ligne. Expliquez ce que vaut this à chaque appel.

  5. 5. Plusieurs constructeurs

    Écrivez trois constructeurs de Document, dont deux qui délèguent au troisième. Vérifiez que la validation n'est écrite qu'une fois.

  6. 6. L'objet non initialisé

    Déclarez une référence sans l'affecter et appelez une méthode dessus. Lisez le message, et distinguez « la référence est nulle » de « l'objet est vide ».

  7. 7. Comparer deux objets

    Créez deux Document de contenu identique et comparez-les avec l'opérateur d'égalité. Expliquez le résultat, et faites de même avec deux chaînes construites de deux façons.

  8. 8. Au fil rouge

    Écrivez la classe Mediatheque contenant un tableau de Document, avec ajouter, chercher et lister. Vérifiez qu'aucune méthode n'a besoin de connaître l'intérieur de Document.

C'est réussi quand
  • Vous expliquez pourquoi le constructeur sans this laisse les champs à null
  • Vos trois constructeurs ne dupliquent aucune validation
  • Vous savez dire ce que compare l'opérateur d'égalité sur deux objets

Ce que la suite en fait

Le chapitre 3 ferme l'objet. Rien n'empêche encore d'écrire a.solde = -1000 de l'extérieur, ce qui ruine tout le bénéfice de l'introduction : la règle est dans la méthode, mais on peut passer à côté. L'encapsulation supprime ce contournement.

Le chapitre 4 reprendra la distinction que l'animation a montrée — variable de classe contre variable d'instance — et la traitera pour elle-même, avec les méthodes statiques et le main.

À retenir

Flashcards · 1 / 5Toucher pour retourner
Fin de la leçon

Vous avez parcouru les 9 sections.

Marquez-la terminée pour faire avancer votre parcours, ou revenez sur un point avant de passer à la suite.