Classes et objets en Java

Apprends à écrire tes propres classes en Java. Définis les champs qui contiennent l’état d’un objet, écris des constructeurs qui donnent à chaque nouvel objet des valeurs initiales valides et ajoute des méthodes d’instance qui utilisent et modifient cet état. Protège tes objets avec des champs privés, des accesseurs, des mutateurs et des vérifications, donne-leur une méthode toString lisible, puis termine en concevant, construisant et testant une classe complète à partir d’une courte description.

DébutantUnité 5 sur 11 de la formation Formation : Java orienté objet : classes, collections, héritage et tests

Ce que tu vas apprendre

  1. Explique comment une classe définit un nouveau type de données doté de son propre comportement, puis crée et utilise des objets de ce type dans un programme.
    • Explique ce que sont une classe et un objet
      Décris une classe comme la définition d’un type, un objet comme une instance de ce type, et l’état et le comportement comme ce que les objets contiennent et font.
    • Crée des objets et appelle leurs méthodes
      Crée des objets avec new, appelle leurs méthodes avec la notation pointée et prévois le comportement d’objets distincts.
  2. Déclare les variables d’instance qui contiennent l’état d’un objet et écris des constructeurs qui donnent à chaque nouvel objet des valeurs initiales valides.
    • Déclare des variables d’instance
      Déclare des champs de types adaptés, connais leurs valeurs par défaut et distingue-les des variables locales et des paramètres.
    • Écris des constructeurs qui initialisent les objets
      Écris des constructeurs qui définissent chaque champ, utilise this pour distinguer les champs des paramètres et évite les erreurs qui laissent des champs sans valeur définie.
    • Propose plusieurs constructeurs et chaîne-les
      Surcharge les constructeurs pour proposer différentes façons de créer un objet et utilise this(...) afin de n’écrire le code d’initialisation qu’une fois.
  3. Écris des méthodes d’instance qui lisent et modifient l’état d’un objet, suis leurs effets et décide quand un élément appartient à un objet ou à la classe entière.
    • Écris des méthodes d’instance qui utilisent et modifient l’état
      Écris des méthodes qui donnent des informations sur les champs d’un objet ou les modifient, appelle d’autres méthodes du même objet et suis l’état des objets étape par étape.
    • Distingue les membres d’instance des membres statiques
      Utilise this pour désigner l’objet courant, décide de ce qui doit être statique et corrige les erreurs dues au mélange de code statique et de code d’instance.
  4. Masque les champs à l’aide de modificateurs d’accès, donne un accès contrôlé par des accesseurs, des mutateurs et des méthodes adaptées, et conserve chaque objet dans un état valide.
    • Masque les données avec des modificateurs d’accès
      Utilise private, l’accès de paquetage, protected et public pour contrôler le code qui peut utiliser les membres d’une classe, et explique pourquoi les champs sont privés.
    • Écris des accesseurs et des mutateurs
      Écris des méthodes d’accès et de modification avec les noms standard, puis décide quels champs en ont besoin et quand une méthode qui décrit une action est préférable.
    • Préserve la validité des objets à l’aide de vérifications
      Définis les règles que l’état d’un objet doit respecter, fais-les appliquer par les constructeurs et les méthodes et évite de fournir des données internes qui permettent de contourner ces vérifications.
  5. Donne aux objets une forme textuelle lisible avec toString, puis conçois, écris et teste une classe complète à partir d’une courte description.
    • Écris une méthode toString
      Écris une méthode toString qui renvoie une description lisible d’un objet et identifie quand Java l’appelle automatiquement.
    • Conçois, construis et teste une classe complète
      Transforme une courte description en une classe avec des champs, des constructeurs, des méthodes et des règles, puis teste chaque comportement depuis un programme principal.

Classes et objets en Java : cours

5 chapitres

1

Classes, objets et appels de méthodes

Un programme doit souvent conserver ensemble plusieurs valeurs liées : le nom, l’espèce et l’âge d’un animal de compagnie, par exemple. Une classe donne un type à ce groupe et rassemble les actions qui l’utilisent. Tu associeras les définitions de classes aux objets créés pendant l’exécution d’un programme, puis tu suivras les appels de méthodes pour voir les données de quel objet changent. La distinction entre une classe, un objet et une variable t’aidera à lire le code que tu écriras ensuite.

1.1 Un type avec un état et un comportement

Une classe définit un type : les données que ses objets mémorisent et les opérations qu’ils proposent. Un objet, aussi appelé instance, est une valeur de ce type créée pendant l’exécution d’un programme. Écrire une définition de classe ne crée pas d’objet.

État et comportement

Le nom, l’espèce et l’âge d’un animal de compagnie constituent son état. Ces valeurs actuelles sont contenues dans des variables d’instance, aussi appelées champs. Une opération comme fêter un anniversaire est un comportement, écrit sous forme de méthode. La méthode d’anniversaire va avec l’âge qu’elle modifie, ce qui permet de garder la règle à un seul endroit.

Imagine une classe comme un plan de construction. Beaucoup de maisons peuvent suivre un même plan, mais chacune possède son propre contenu. De même, deux animaux peuvent suivre la même définition et avoir des âges différents. Tu écris les noms des champs une seule fois ; chaque objet reçoit ses propres valeurs.

Lis une petite classe
public class Pet {
    private String name;
    private String species;
    private int age;

    public Pet(String name, String species, int age) {
        this.name = name;
        this.species = species;
        this.age = age;
    }

    public void celebrateBirthday() {
        this.age++;
    }
}

Lis ce code de l’extérieur vers l’intérieur. public class Pet introduit le type et les accolades extérieures contiennent sa définition. Les trois premières déclarations décrivent l’état. Le bloc nommé Pet est un constructeur : il donne ses premières valeurs à un nouvel objet. celebrateBirthday est une méthode : elle augmente l’âge de l’objet courant. Les mots private et public contrôlent l’accès ; les exemples suivants les utilisent pour protéger l’état.

Les paramètres du constructeur sont des valeurs fournies lors de la création d’un objet. Dans this.age = age;, le côté gauche désigne le champ de l’objet et le côté droit le paramètre fourni. Le constructeur stocke cette donnée pour que l’objet puisse la mémoriser après la fin de sa construction.

Utilise une classe

Tu as déjà utilisé des classes de bibliothèque. Scanner décrit des objets qui lisent des données en entrée, ArrayList décrit des listes et un objet String propose des opérations comme length(). Une classe que tu écris suit le même principe : elle met un type utile à la disposition du reste de ton programme.

Sans Pet, un programme pourrait transmettre séparément un nom, une espèce et un âge à de nombreuses méthodes. Il devrait maintenir correctement chaque groupe de valeurs. Un objet Pet réunit les valeurs liées en une seule entité. Les méthodes de cet objet savent quel âge elles doivent utiliser.

Organise et nomme le code

Pour les fichiers source ordinaires, une classe publique nommée Pet est enregistrée dans Pet.java, en respectant les majuscules. Une classe Main distincte peut contenir la méthode main du programme, créer des animaux et appeler leurs méthodes. Pet n’a pas besoin de sa propre méthode main. Les classes d’un même paquetage sans nom peuvent s’utiliser entre elles sans importation ; les exemples simples placent ces classes dans un même dossier.

Utilise des noms en UpperCamelCase pour les classes, comme LibraryBook. Utilise lowerCamelCase pour les champs et les méthodes : pageCount nomme une donnée ; giveBack() nomme une action. Ces conventions aident le lecteur à reconnaître chaque élément, même si le compilateur autorise bien d’autres noms.

Points clés

  • Une classe définit un type ; un objet est une instance créée pendant l’exécution du programme.
  • Les champs contiennent l’état et les méthodes définissent le comportement.
  • Les objets d’une même classe suivent la même définition et possèdent leurs propres valeurs de champs d’instance.
  • Dans un fichier source ordinaire, le nom du fichier d’une classe publique correspond au nom de la classe.

1.2 Nouveaux objets et références qui les désignent

Créer un objet et déclarer une variable sont deux opérations différentes. Une variable te donne un nom par lequel accéder à un objet ; new crée l’objet auquel ce nom fera référence.

Lis une instruction de création d’objet
Pet luna = new Pet("Luna", "cat", 3);

Pet est le type de la variable et luna est son nom. new Pet(...) crée un nouvel objet et appelle un constructeur correspondant avec trois arguments. Le constructeur stocke le nom, l’espèce et l’âge. La référence obtenue est affectée à luna.

Une référence indique à Java quel objet utiliser. Il est utile de représenter une variable par un nom accompagné d’une flèche vers un objet. La variable n’est pas une deuxième copie de tous les champs de l’objet.

Appelle une méthode sur un objet précis

Le point dans luna.celebrateBirthday() relie une référence à une méthode à exécuter sur son objet. Une méthode qui renvoie une valeur peut la fournir à une autre expression :

luna.celebrateBirthday();
int years = luna.getAge();
System.out.println(years); // 4

Ici, getAge() est une méthode publique qui renvoie l’âge de l’animal. L’appel lié à l’anniversaire modifie l’état ; l’accesseur lit cet état. Pet.celebrateBirthday() échoue parce que cette méthode d’instance a besoin d’un animal précis. Le nom de la classe seul ne dit pas de quel anniversaire il s’agit.

Objets distincts et références partagées
Pet max = new Pet("Max", "dog", 5);
luna.celebrateBirthday();
System.out.println(luna.getAge()); // 5
System.out.println(max.getAge());  // 5

Luna avait déjà 4 ans, donc l’anniversaire suivant la fait passer à 5 ans. Max reste à 5 ans. Des âges égaux ne font pas d’eux un même objet : les deux expressions new ont créé des animaux distincts.

Considère maintenant une affectation sans new :

Pet other = luna;
other.celebrateBirthday();
System.out.println(luna.getAge()); // 6

L’affectation copie la référence vers Luna. Les deux noms donnent accès au même animal : une modification effectuée par other est donc visible par luna. Pour créer un deuxième animal, appelle new à nouveau.

Respecte les paramètres du constructeur

Les arguments doivent correspondre au nombre, à l’ordre et aux types des paramètres d’un constructeur déclaré. Si le seul constructeur disponible prend (String, String, int), new Pet() ne se compile pas. Java ne devine pas les valeurs manquantes. En revanche, inverser les deux chaînes se compile quand même : new Pet("cat", "Luna", 3) fournit les bons types mais pas les bonnes significations. Lis les noms des paramètres pour vérifier leur ordre.

Ces deux tentatives inachevées échouent pour des raisons différentes :

Pet a;                         // declaration only
// System.out.println(a.getAge()); // a has no assigned value
// Pet b = Pet("Bo", "cat", 2);    // missing new

Une valeur doit être affectée à une variable locale avant son utilisation. Sans new, Java cherche une méthode nommée Pet, pas une expression de création d’objet. Une fois l’objet créé, l’afficher peut montrer un texte comme Pet@8bcc55f tant que tu ne fournis pas une méthode toString() lisible ; cette sortie ne signifie pas que la construction a échoué.

Points clés

  • Utilise new avec des arguments qui correspondent à un constructeur disponible.
  • La notation pointée appelle une méthode d’instance sur l’objet désigné par une référence.
  • Une nouvelle expression new crée un autre objet ; l’affectation d’une référence permet de partager un objet existant.
  • Des arguments de même type peuvent être inversés sans erreur du compilateur : vérifie donc leur signification.
  • Une déclaration locale seule ne crée aucun objet et ne donne à la variable aucune valeur utilisable.
2

Champs et état initial d’un objet

Les objets ont besoin d’un endroit où conserver leurs données et d’un moyen fiable d’obtenir leurs premières valeurs. Les champs fournissent le stockage ; les constructeurs initialisent chaque nouvel objet. Tu choisiras les types des champs, distingueras l’état durable du travail local temporaire et suivras la construction, des valeurs par défaut à un objet prêt à l’emploi. Tu proposeras ensuite plusieurs façons utiles de créer un même type d’objet tout en conservant l’initialisation et les vérifications communes à un seul endroit.

2.1 Les données qu’un objet mémorise

Un objet a besoin d’un champ pour chaque valeur qu’il doit mémoriser entre deux appels de méthode. Choisis ces valeurs avant d’écrire les méthodes : elles constituent l’état durable de l’objet.

Déclare des champs de types adaptés

Un champ se trouve entre les accolades de la classe, mais en dehors de tout constructeur et de toute méthode. Une déclaration comporte nécessairement un type et un nom ; elle peut aussi comporter un modificateur d’accès et un initialiseur.

private String title;
private int pageCount;
private boolean lentOut = false;

String convient au texte, int au dénombrement par un entier et boolean à une condition dont la réponse est oui ou non. Les champs peuvent aussi utiliser des types définis par des classes comme ArrayList<String>. Ces exemples utilisent private ; omettre le modificateur donne un accès de paquetage, pas un accès privé.

Chaque objet reçoit une copie distincte de chaque champ d’instance. Deux objets Rectangle ont chacun un champ width et un champ height, même si les déclarations n’apparaissent qu’une fois dans la classe.

Les valeurs par défaut ne sont pas toujours des valeurs initiales utilisables
Type du champValeur par défaut
int, long0
double0.0
booleanfalse
Types définis par des classes, dont String et ArrayListnull

Une valeur par défaut est affectée à un champ lorsque l’espace de stockage de l’objet est créé. Elle peut ne pas convenir à l’usage de l’objet. Un champ de type liste dont la valeur est null n’est pas une liste vide : tu dois encore créer la liste avant d’y ajouter un élément.

Les variables locales ne reçoivent pas de telle valeur par défaut. Dans une méthode, int total; suivi de System.out.println(total); ne se compile pas parce qu’aucune valeur n’a été affectée à total. Distingue bien la règle des champs de celle des variables locales.

Décide ce qui doit durer
Type de variableOù elle est déclaréeÀ quoi elle sert
Champ d’instanceDans la classe, en dehors des méthodesValeurs mémorisées par un objet
ParamètreDans l’en-tête d’un constructeur ou d’une méthodeDonnées fournies pour cet appel
Variable localeDans un bloc de méthode ou de constructeurTravail temporaire pour cet appel

Un champ reste associé à son objet. Un paramètre est disponible pendant son appel et une variable locale est disponible dans son bloc pendant l’exécution de cet appel. Si un compteur doit conserver son compte d’un appel à l’autre, le compte doit être placé dans un champ. Un sous-total temporaire utilisé pour un calcul peut être local.

Stocke les données ; calcule les valeurs dérivées
public class Rectangle {
    private double width;
    private double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    public double area() {
        return this.width * this.height;
    }
}

Les dimensions sont en centimètres, donc area() renvoie une aire en centimètres carrés. Stocker l’aire dans un champ distinct créerait une valeur supplémentaire à mettre à jour chaque fois que l’une des dimensions change. La calculer à partir des dimensions garantit la cohérence du résultat.

Utilise un champ d’instance final pour une valeur affectée une seule fois, comme private final String title;. Donne-lui une valeur dans sa déclaration ou dans chaque constructeur. final empêche toute réaffectation. static a un sens différent : il crée un champ de classe partagé. Ajouter static au nom d’un animal ferait partager une seule variable de nom à plusieurs animaux.

Points clés

  • Les champs d’instance sont déclarés en dehors des méthodes et mémorisent l’état de chaque objet.
  • Les champs reçoivent des valeurs par défaut ; les variables locales doivent recevoir une valeur avant leur utilisation.
  • Choisis des champs pour les données durables et des variables locales pour le travail temporaire.
  • Calcule les valeurs qui découlent des champs stockés pour éviter les copies incohérentes.
  • Un champ d’instance final reçoit une valeur une seule fois ; un champ statique est partagé par la classe.
  • Un champ de type liste qui vaut null a encore besoin d’un objet liste avant de pouvoir être utilisé.

2.2 Des arguments aux champs initialisés

Un constructeur initialise un objet lorsque new le crée. Son nom doit correspondre à celui de la classe et il n’a pas de type de retour. Même void transformerait la déclaration en méthode.

Transfère les données dans l’état
public Pet(String name, String species, int age) {
    this.name = name;
    this.species = species;
    this.age = age;
}

Un constructeur accepte généralement des données sous forme de paramètres et les stocke dans des champs. Ici, chaque paramètre porte le même nom que son champ. Le nom seul age désigne le paramètre ; this.age désigne le champ de l’objet en cours de création. L’affectation lit la valeur fournie à droite et l’écrit dans le champ à gauche.

Pour new Pet("Luna", "cat", 3), les champs du nouvel objet reçoivent d’abord les valeurs par défaut : null, null et 0. Le constructeur reçoit ensuite les trois arguments et remplace ces valeurs. Une fois la construction terminée, new produit la référence que l’appelant stocke.

Deux bogues qui se compilent
public Pet(String name, String species, int age) {
    name = name;
    this.species = species;
    this.age = age;
}

Les deux occurrences de name désignent le paramètre : la première ligne affecte donc au paramètre sa propre valeur. Le nom de l’objet reste à null. Le code est valide, d’où l’importance de vérifier les valeurs du nouvel objet.

Une déclaration dans le constructeur provoque un problème similaire :

String nick = initialNick;

Si un champ nommé nick existe déjà, cette ligne crée une variable locale de même nom. La variable locale disparaît à la fin de la construction. Écris this.nick = initialNick; pour stocker la donnée dans le champ ; ne répète pas le type.

Sache quand un constructeur sans argument existe

Si une classe ne déclare aucun constructeur, Java fournit un constructeur par défaut sans paramètre. Pour une classe simple, ses champs conservent leurs valeurs initiales déclarées ou leurs valeurs par défaut. Dès que tu déclares un constructeur, Java cesse de fournir ce constructeur par défaut.

Une classe qui possède seulement Pet(String name, String species, int age) ne peut donc pas être instanciée avec new Pet(). Ajoute un constructeur explicite sans argument uniquement lorsqu’il existe un état initial utile pour celui-ci. Fais aussi attention à public void Pet(...) : c’est une méthode, elle ne fournit donc pas du tout le constructeur souhaité.

Définis aussi les valeurs initiales internes

Tous les champs n’ont pas besoin de provenir d’un argument. Un nouveau livre peut toujours commencer avec this.lentOut = false;. Une classe qui possède une liste peut l’initialiser ainsi, après importation de ArrayList :

private ArrayList<String> tracks;

public Playlist() {
    this.tracks = new ArrayList<>();
}

La liste vide est prête pour add. Laisser tracks à null provoque ensuite l’échec de tracks.add(...) avec une NullPointerException.

Un initialiseur de champ s’exécute avant le corps du constructeur. Si private int score = 10; est suivi de this.score = 5; dans le constructeur, le score de l’objet terminé est 5. Teste les valeurs après la construction, pas seulement les valeurs écrites à côté des déclarations de champs. Les constructeurs doivent aussi appliquer les mêmes règles de validation que les modifications ultérieures, afin que l’état initial soit valide.

Points clés

  • Un constructeur porte le nom de la classe et n’a pas de type de retour.
  • Utilise this.field = parameter lorsque les noms sont identiques.
  • Ni l’affectation d’un paramètre à lui-même ni la création d’une variable locale n’initialise le champ visé.
  • Java ne fournit un constructeur par défaut que si la classe ne déclare aucun constructeur.
  • Initialise l’état interne, comme les listes vides, et applique les règles de validation pendant la construction.

2.3 Plusieurs façons de construire un même type d’objet

Une classe peut proposer plusieurs façons utiles de créer un objet. La surcharge de constructeurs consiste à déclarer des constructeurs dont les listes de paramètres sont différentes.

Distingue les constructeurs par leurs paramètres

Java distingue les constructeurs par le nombre, les types et l’ordre de leurs paramètres. Les noms des paramètres ne permettent pas de les distinguer. Box(String label) et Box(String name) décrivent la même liste de paramètres : ils ne peuvent donc pas être tous deux déclarés dans une même classe.

Un animal peut être créé avec un âge ou comme nouveau-né :

public Pet(String name, String species, int age) {
    this.name = name;
    this.species = species;
    this.age = age;
}

public Pet(String name, String species) {
    this(name, species, 0);
}

new Pet("Pip", "rabbit") sélectionne le constructeur à deux paramètres. Ce constructeur fournit 0 pour l’âge manquant et appelle le constructeur à trois paramètres. L’état du nouvel objet contient finalement "Pip", "rabbit" et 0.

Chaîne l’initialisation sur le même objet

Dans un constructeur, this(...) appelle un autre constructeur de la même classe. Le constructeur le plus court choisit des valeurs par défaut ; le constructeur le plus complet effectue l’initialisation commune. Les vérifications placées dans cette initialisation s’appliquent aux deux façons de construire l’objet.

Compare deux lignes qui se ressemblent :

Ligne dans un constructeurEffet
this(name, species, 0);Initialise l’objet courant par l’intermédiaire d’un autre constructeur
new Pet(name, species, 0);Crée un animal distinct

La deuxième ligne ne remplit pas les champs de l’objet courant. Si son résultat n’est jamais stocké, cet animal supplémentaire est abandonné. Les champs de l’animal courant peuvent encore valoir null.

Suis une chaîne avant de suivre le reste du code

Une horloge peut proposer minuit comme valeur par défaut :

public Clock() {
    this(0, 0);
}

public Clock(int hours, int minutes) {
    this.hours = hours;
    this.minutes = minutes;
}

Pour new Clock(), entre dans le constructeur sans argument, suis this(0, 0) et affecte les deux champs dans le constructeur à deux arguments. L’exécution revient ensuite au constructeur sans argument. Cela crée une seule horloge, pas deux. Un appel à new Clock(9, 5) démarre directement dans le constructeur le plus complet.

Garde une chaîne valide et claire

Un constructeur peut contenir au maximum un appel this(...). La chaîne doit finir par atteindre une initialisation qui ne rappelle pas un constructeur de la chaîne : deux constructeurs qui délèguent l’un à l’autre provoquent une erreur de compilation due à un appel récursif de constructeur.

Placer this(...) en premier est un style clair qui fonctionne dans toutes les versions de Java. Dans Java 24 et les versions antérieures sans fonctionnalités en avant-première, l’appel doit être en premier. Java 25 autorise des instructions avant cet appel, par exemple pour calculer ou vérifier des arguments. Ces instructions ne peuvent ni lire les champs d’instance de l’objet courant ni appeler ses méthodes d’instance ; les affectations aux champs déclarés dans la classe sans initialiseur dans leur déclaration sont autorisées.

Propose des surcharges parce que les appelants disposent de différentes données utiles. Une horloge réglée à minuit a un sens ; un livre sans titre n’en a pas forcément. L’existence d’un constructeur complet ne crée automatiquement aucune surcharge plus courte.

Points clés

  • Les constructeurs surchargés se distinguent par leurs listes de paramètres, pas par les noms de ces paramètres.
  • L’appel this(...) délègue à un autre constructeur sur le même objet.
  • Garde l’initialisation et les vérifications communes dans un seul chemin de construction.
  • Une chaîne de constructeurs ne doit pas revenir à un constructeur qui en fait déjà partie.
3

Méthodes qui lisent et modifient l’état

Un objet utile peut répondre à des questions sur lui-même et effectuer des actions qui modifient son état. Les méthodes d’instance placent ces opérations à côté des champs qu’elles utilisent. Tu suivras les modifications instruction par instruction, géreras le passage d’une heure à l’autre sur une horloge et renverras des valeurs utilisables par d’autres parties du code. Tu décideras aussi quelles données appartiennent à chaque objet et quelles données ou opérations appartiennent à la classe, afin que les objets distincts restent indépendants.

3.1 Calculs, modifications et traces des états

Une méthode d’instance s’exécute pour un objet précis. Déclare-la sans static et utilise les champs de cet objet avec des noms comme this.width. Décide de ce dont l’appelant a besoin : une modification de l’état, un résultat renvoyé ou les deux.

Renvoie les résultats des calculs ; rends explicites les modifications de l’état

Pour un rectangle dont les dimensions sont stockées en centimètres :

public double area() {
    return this.width * this.height;
}

public double perimeter() {
    return 2 * (this.width + this.height);
}

public void scale(double factor) {
    this.width = this.width * factor;
    this.height = this.height * factor;
}

Un rectangle de côtés 3,0 et 4,0 a une aire de 12,0 centimètres carrés et un périmètre de 14,0 centimètres. scale(2) fait passer les côtés à 6,0 et 8,0. Les appels suivants renvoient une aire de 48,0 et un périmètre de 28,0. Chaque méthode lit les champs actuels : aucune aire stockée n’a donc besoin d’être mise à jour.

area() renvoie un nombre qui peut être stocké ou utilisé dans un calcul. Si elle ne faisait qu’afficher le nombre et avait le type de retour void, l’appelant ne pourrait pas écrire double twice = r.area() * 2;. Laisse l’affichage à l’appelant lorsque le rôle d’une méthode est de calculer une valeur.

Mets à jour les champs liés dans l’ordre

La méthode advance() d’une horloge doit gérer le passage à l’heure et au jour suivants :

public void advance() {
    this.minutes++;
    if (this.minutes == 60) {
        this.minutes = 0;
        this.hours++;
        if (this.hours == 24) {
            this.hours = 0;
        }
    }
}

À 23 h 58, le premier appel atteint 23 h 59 et saute les deux blocs de remise à zéro. L’appel suivant atteint brièvement la minute 60, la remet à 0, fait passer l’heure à 24, puis la remet à 0. L’état final est 00 h 00. Un appel de plus donne 00 h 01.

Suis les objets séparément

Écris une ligne après chaque instruction et une colonne pour les champs de chaque objet. Ne modifie que l’objet désigné par le receveur de l’appel. Pour des animaux âgés de 2 et 7 ans, deux anniversaires pour le premier et setAge(1) pour le second donnent finalement les âges 4 et 1. N’exécute pas le corps d’une méthode pour toutes les instances simplement parce qu’elles partagent une classe.

Une déclaration locale peut masquer le champ que tu voulais mettre à jour. public void reset() { int count = 0; } ne crée qu’une variable temporaire. this.count = 0; remet à zéro le compte durable.

Réutilise les méthodes et complète les chemins de retour

Dans une méthode d’instance, area() et this.area() appellent la méthode de calcul de l’aire du même objet. Une méthode de description peut réutiliser ce calcul au lieu de copier son expression. Une méthode peut aussi modifier l’état et renvoyer une indication de réussite, comme lend() lorsqu’elle marque un livre comme emprunté et renvoie true.

Une méthode dont le type de retour est différent de void ne peut pas simplement atteindre sa fin sans renvoyer une valeur compatible. Si get() ne renvoie une valeur que dans if (count > 0), que se passe-t-il lorsque le compte vaut 0 ? Ajoute le chemin de retour nécessaire ou lève une exception pour une valeur que la méthode rejette. Un chemin qui lève une exception ne rend pas la main à l’appelant et n’a pas besoin de valeur de retour.

Points clés

  • Les méthodes d’instance lisent ou modifient l’état de l’objet sur lequel elles sont appelées.
  • Renvoie les valeurs calculées pour que les appelants puissent les utiliser dans des expressions.
  • Suis les instructions dans l’ordre, en gardant séparés les champs de chaque objet.
  • Les méthodes qui gèrent un passage à la valeur suivante doivent ramener chaque champ concerné dans son intervalle autorisé.
  • Réutilise d’autres méthodes du même objet en les appelant directement ou avec this.
  • Une méthode qui renvoie une valeur doit en fournir une sur chaque chemin qui se termine normalement.

3.2 Membres propres aux objets et membres de classe partagés

Demande-toi à qui appartient une valeur ou une opération avant de décider d’utiliser static. L’âge d’un animal appartient à cet animal. Le nombre de tous les animaux créés appartient à la classe entière.

L’objet courant est this

Dans un constructeur ou une méthode d’instance, this désigne l’objet en cours de construction ou celui qui reçoit l’appel. Dans this.age++, il indique l’objet dont l’âge change. Dans this.name = name, il distingue le champ d’un paramètre de même nom. this(...) est la forme utilisée pour chaîner les constructeurs.

Une méthode statique n’a pas d’objet courant : this ne peut donc pas y être utilisé. Elle peut toutefois créer un objet ou recevoir une référence et l’utiliser pour appeler des méthodes d’instance.

Champs partagés et champs propres aux objets
public class Counter {
    private int count;
    private static int created = 0;

    public Counter() {
        this.count = 0;
        created++;
    }

    public void increment() {
        this.count++;
    }

    public int getCount() {
        return this.count;
    }

    public static int getCreated() {
        return created;
    }
}

Après deux appels à new Counter(), il y a deux champs count distincts, initialement égaux à 0, et un champ created égal à 2. Incrémenter le premier compteur fait passer son compte à 1 ; celui du second reste à 0. Counter.getCreated() renvoie toujours 2, car aucun nouvel objet n’a été construit.

Utilise un objet depuis main
public static void main(String[] args) {
    Counter c = new Counter();
    c.increment();
    System.out.println(c.getCount());
}

La méthode main classique est statique. Un appel à increment() seul à cet endroit n’aurait pas d’objet cible et ne se compilerait pas. La variable c fournit cette cible. Rendre count statique pour faire disparaître l’erreur changerait la conception : tous les compteurs partageraient alors un seul compte.

Type de méthodeAccès direct disponible
Méthode d’instanceSes membres d’instance et les membres statiques de la classe
Méthode statiqueMembres statiques ; membres d’instance par une référence vers un objet

Java 25 prend aussi en charge des formes de main sous forme de méthode d’instance, mais l’en-tête statique classique reste valide. Ces exemples l’utilisent systématiquement.

Choisis les méthodes et les constantes avec soin

Une opération qui a besoin des champs d’un objet devrait être une méthode d’instance. Une opération qui dépend uniquement de ses paramètres peut être statique, comme une méthode auxiliaire qui convertit un nombre total de minutes en heures. Les appels statiques utilisent normalement le nom de la classe : Math.sqrt(16) ou Counter.getCreated().

Une valeur fixe partagée est généralement déclarée comme une constante :

public static final int MAX_CELSIUS = 30;

public la rend accessible aux appelants, static donne à la classe un champ partagé unique et final empêche sa réaffectation. Par convention, UPPER_SNAKE_CASE indique une constante. C’est une exception courante à la règle qui rend les champs privés. N’utilise pas static pour les noms, les dimensions ou tout autre élément d’état ordinaire qui doit différer d’un objet à l’autre.

Points clés

  • La référence this désigne l’objet courant dans le code d’instance.
  • Les membres statiques appartiennent à la classe ; les membres d’instance appartiennent à chaque objet.
  • Une méthode statique a besoin d’une référence vers un objet pour utiliser des membres d’instance.
  • Corrige les erreurs de contexte statique en fournissant l’objet approprié lorsque l’état appartient à un objet.
  • Un champ public static final fournit couramment une constante partagée.
4

Accès contrôlé et état valide

Une classe devrait contrôler les valeurs qui peuvent entrer dans son état. Les champs privés et les méthodes publiques lui permettent de vérifier chaque modification et de fournir aux appelants des opérations utiles. Tu choisiras des niveaux d’accès, écriras des accesseurs et des mutateurs lorsqu’ils sont utiles et protégeras des règles comme un intervalle de températures autorisé. Tu verras aussi pourquoi une liste privée peut être exposée par un accesseur et comment empêcher le code extérieur de contourner les vérifications de la classe.

4.1 État privé et interface publique

L’encapsulation rassemble l’état d’un objet et le code qui le contrôle. Les champs sont généralement privés, tandis que les appelants utilisent des opérations publiques. Cela masque les détails du stockage et donne à la classe un endroit où faire appliquer ses règles.

Choisis un niveau d’accès
AccèsQui peut utiliser le membre
privateLe code de la même classe
Aucun modificateurLe code du même paquetage
protectedLe même paquetage, ainsi que les sous-classes selon les règles d’accès de Java
publicLe code qui peut accéder au type déclarant

Un paquetage regroupe des classes. Les exemples simples placent des classes ordinaires ensemble sans déclaration package, dans un seul paquetage sans nom. L’accès de paquetage résulte de l’omission du modificateur ; il n’existe pas de mot-clé d’accès package à ajouter à un champ.

Commence par l’accès utile le plus restrictif. Rends les champs privés, les constructeurs et les opérations nécessaires aux autres classes publics, et les méthodes auxiliaires internes privées. Les constantes publiques sont une exception courante pour les champs.

Confie à la classe le contrôle des modifications

Si Pet déclare private int age;, une classe Main distincte ne peut pas effectuer l’affectation luna.age = -5;. Le compilateur rejette cet accès. Un appel comme luna.setAge(-5) peut être autorisé, car la méthode publique appartient à Pet et peut décider de stocker ou non l’argument.

Un champ public permettrait à tout appelant de contourner cette méthode. Lorsque toutes les modifications passent par le code de la classe, les vérifications peuvent être regroupées à un seul endroit. L’accès privé seul ne valide pas un âge ; les méthodes doivent aussi effectuer les vérifications.

Garde l’interface publique stable

Supposons qu’une horloge stocke initialement les champs distincts hours et minutes. Les appelants utilisent getHours() et getMinutes(). Tu remplaces ensuite les champs par une seule valeur minutesSinceMidnight :

public int getHours() {
    return this.minutesSinceMidnight / 60;
}

public int getMinutes() {
    return this.minutesSinceMidnight % 60;
}

Avec 615 minutes stockées, la division renvoie 10 et le reste vaut 15. L’horloge indique 10 h 15 par les mêmes méthodes. Le code des appelants n’a pas besoin d’être réécrit, car il dépendait des opérations publiques, pas de la façon dont l’état était stocké. Cette liberté de modifier les éléments internes est le masquage de l’information.

L’accès dépend des classes, pas des objets individuels

Le code dans Pet peut lire un champ privé d’un autre objet Pet. L’autorisation d’accès vient du fait que le code se trouve dans la classe. Une autre classe de premier niveau n’obtient pas cette autorisation en possédant une référence vers un animal ou en se trouvant dans le même dossier.

Pour les déclarations ordinaires de classes de premier niveau, les choix d’accès sont public ou aucun modificateur. Une déclaration private class Pet au premier niveau est interdite. Une classe publique de premier niveau va dans le fichier source correspondant, et un fichier source ordinaire contient au maximum une classe publique de premier niveau.

Les champs privés constituent une frontière dans la conception du programme. Ils empêchent le reste du code ordinaire de dépendre directement des champs internes, mais ne permettent pas de garder une valeur secrète pour une personne qui peut examiner le programme. Utilise-les pour contrôler l’interface de ta classe et protéger son état.

Points clés

  • Les champs privés et les opérations publiques conservent le contrôle de l’état dans la classe.
  • Omettre un modificateur d’accès donne un accès de paquetage.
  • Les méthodes publiques permettent de modifier le stockage interne sans modifier le code des appelants.
  • L’accès privé est vérifié par classe : le code dans la classe peut donc accéder aux champs d’une autre instance.
  • Les classes ordinaires de premier niveau utilisent l’accès public ou l’accès de paquetage.

4.2 Des méthodes d’accès adaptées à la classe

Une classe peut permettre aux appelants de lire ou de modifier certaines parties de son état par l’intermédiaire de méthodes. Décide des opérations que la classe devrait proposer avant de créer des méthodes d’accès pour chaque champ.

Renvoie des valeurs avec des accesseurs

Un accesseur, aussi appelé méthode d’accès, renvoie des informations sans modifier l’objet. Un accesseur courant lit un champ :

public String getName() {
    return this.name;
}

public int getAge() {
    return this.age;
}

Le type de retour correspond à l’information fournie. Un accesseur qui affiche une valeur et renvoie void ne peut pas fournir de valeur à une expression comme pet.getAge() + 1. L’appelant devrait recevoir la valeur et décider comment l’utiliser.

Modifie certaines valeurs avec des mutateurs

Un mutateur, aussi appelé méthode de modification, reçoit une nouvelle valeur et met à jour l’état :

public void setName(String name) {
    this.name = name;
}

this.name est le champ. name est le paramètre. Écrire name = name; se compile mais ne modifie aucun champ. Il n’y a pas de valeur de retour ici, car le rôle de ce mutateur est d’effectuer une modification.

Pour un animal âgé de 3 ans :

luna.setName("Lulu");
System.out.println(luna.getName() + " is " + luna.getAge());
// Lulu is 3

L’appelant ne touche jamais directement à un champ. Le mutateur modifie le nom et les accesseurs renvoient les valeurs actuelles que l’appelant peut combiner.

Respecte les noms attendus par les autres codes Java
ChampAccesseurMutateur, si nécessaire
pageCountgetPageCount()setPageCount(int pageCount)
namegetName()setName(String name)
lentOutisLentOut()setLentOut(boolean lentOut)

Mets en majuscule la première lettre du nom du champ après get, set ou le préfixe booléen habituel is. Un nom comme getname() peut se compiler, mais il ne suit pas la convention attendue par les outils et les autres programmeurs.

N’expose que les opérations utiles

Le titre d’un livre peut avoir un accesseur et aucun mutateur, car les appelants devraient pouvoir le lire sans le remplacer. Un champ privé final peut garantir qu’il ne reçoit une valeur qu’une fois. Un compteur interne peut n’avoir besoin ni d’accesseur ni de mutateur si seule la classe l’utilise.

Un mutateur sans vérification peut accepter la même valeur dommageable qu’un champ public. Ajoute des vérifications lorsqu’une modification est soumise à des restrictions. Envisage aussi une méthode d’action : celebrateBirthday() exprime l’augmentation de l’âge d’un an et lend() exprime une tentative de prêt. lend() peut examiner l’état courant et refuser un deuxième prêt. Un mutateur peut aussi effectuer cette vérification ; le nom de l’action rend l’opération plus claire pour son appelant.

Un accesseur peut calculer un résultat. getArea() peut renvoyer le produit de la largeur par la hauteur sans aucun champ area.

Points clés

  • Un accesseur renvoie une information ; un mutateur modifie une valeur donnée.
  • Suis le modèle de nommage getName, setName et, pour les booléens, l’habituel isName.
  • Ne donne aux champs que les méthodes d’accès dont les appelants ont besoin.
  • Les méthodes d’action comme lend expriment clairement les comportements autorisés et peuvent vérifier les changements d’état.

4.3 Des règles qui résistent à chaque modification

Un invariant est une règle sur l’état d’un objet qui reste vraie après la construction et après chaque opération publique. Un thermostat peut autoriser des températures cibles de 5 °C à 30 °C. Chaque moyen de définir sa cible doit respecter cet intervalle.

Choisis comment traiter une entrée invalide

Trois réponses utiles consistent à conserver l’ancienne valeur, à ramener la valeur à une borne ou à lever une exception. Leurs effets sont différents : choisis donc une réponse claire pour chaque opération.

RéponseRésultat d’un appel invalide
IgnorerL’ancienne valeur du champ reste inchangée
ÉcrêterLa borne autorisée la plus proche est stockée
Lever une exceptionL’appel s’arrête avec une erreur comme IllegalArgumentException

Pour un âge d’animal qui ne doit pas être négatif, un mutateur qui ignore les valeurs invalides peut effectuer l’affectation uniquement dans if (age >= 0). Si l’âge stocké est 4, setAge(-2) le laisse à 4. Il ne le remplace pas par 0.

Place les vérifications d’intervalle dans la classe
public static final int MIN_CELSIUS = 5;
public static final int MAX_CELSIUS = 30;
private int target;

public void setTarget(int celsius) {
    if (celsius < MIN_CELSIUS) {
        this.target = MIN_CELSIUS;
    } else if (celsius > MAX_CELSIUS) {
        this.target = MAX_CELSIUS;
    } else {
        this.target = celsius;
    }
}

public void raise() {
    setTarget(this.target + 1);
}

En partant de 20 °C, setTarget(35) stocke 30. setTarget(-3) stocke 5. Après setTarget(29), un appel à raise() stocke 30 ; un autre appel stocke encore 30. Réutiliser le mutateur empêche raise() de dépasser la borne supérieure.

Des vérifications uniquement dans Main ne peuvent pas protéger le thermostat. Un autre appelant pourrait les oublier. La classe doit vérifier la donnée à l’endroit où elle contrôle son stockage.

Valide aussi l’état initial
public Thermostat(int target) {
    setTarget(target);
}

Avec ce constructeur qui effectue un écrêtage, new Thermostat(50) aboutit à 30 °C. Affecter directement this.target = target; autoriserait un état initial invalide de 50. Une méthode privée de vérification partagée est une autre façon de réutiliser la validation dans les constructeurs et les méthodes ultérieures.

Lever une exception est utile lorsqu’un argument invalide révèle une erreur de programmation. Par exemple, un constructeur peut rejeter un compte négatif avec throw new IllegalArgumentException("count must not be negative");. L’objet n’est pas construit avec succès, donc aucun objet terminé invalide n’est transmis à l’appelant. Ignorer une entrée est plus simple mais silencieux ; l’appelant peut avoir besoin d’un autre moyen de remarquer que rien n’a changé.

Garde les données internes mutables à l’intérieur

Une liste privée peut tout de même être exposée si un accesseur renvoie la liste originale. Un appelant pourrait alors ajouter ou supprimer des éléments sans utiliser les méthodes de la classe, en contournant une règle de taille maximale.

Pour un champ ArrayList<String> nommé tracks, return new ArrayList<>(this.tracks); fournit une liste distincte contenant les mêmes chaînes. Modifier cette liste renvoyée ne change pas la liste interne. Des opérations comme addTrack(String title) permettent de garder les modifications de la liste dans la classe et d’en vérifier les règles avant de les accepter.

Points clés

  • Un invariant reste vrai après la construction et après chaque opération publique.
  • Ignorer une entrée invalide, l’écrêter et lever une exception sont des réponses différentes.
  • Chaque constructeur et chaque méthode qui modifie l’état doivent préserver les mêmes règles.
  • Réutilise la validation pour qu’aucune voie de modification ne puisse la contourner.
  • Renvoyer une liste interne mutable permet aux appelants de contourner les vérifications de la classe.
  • Une copie d’une liste interne de chaînes protège la liste originale des modifications extérieures de la liste.
5

Objets lisibles et classes complètes

Des descriptions lisibles des objets facilitent l’utilisation et la vérification d’une classe. Une méthode toString fournit ce texte chaque fois qu’un objet est affiché ou concaténé à une chaîne. Tu écriras la méthode avec le bon en-tête, puis tu réuniras champs, constructeurs, méthodes et validation dans une classe complète. À partir d’une courte description, tu transformeras les exigences en code et testeras les appels ordinaires, les actions répétées et les cas limites.

5.1 Une description d’objet renvoyée sous forme de texte

Un objet utile devrait être facile à examiner sous forme de texte. La méthode Java intégrée toString() renvoie un nom de classe, un signe @ et un code de hachage hexadécimal, par exemple Pet@8bcc55f. Un paquetage nommé fait partie du nom de la classe. Le texte du code de hachage varie et donne généralement peu d’informations sur l’état de l’objet.

Renvoie une description lisible
@Override
public String toString() {
    return this.name + " (" + this.species + ", "
        + this.age + " years)";
}

Pour Luna, une chatte âgée de 3 ans, la chaîne renvoyée est "Luna (cat, 3 years)". La méthode lit les champs et construit une chaîne. Elle ne modifie pas l’animal et n’affiche rien à l’écran.

@Override demande au compilateur de vérifier que la déclaration remplace bien une méthode existante. Cela permet de détecter des erreurs comme écrire tostring avec un s minuscule. L’annotation ne formate pas le résultat à ta place ; c’est l’expression de retour qui détermine le texte.

Reconnais les appels automatiques
System.out.println(luna);
String label = "Pet: " + luna;
String details = luna.toString();

La première ligne affiche la description lisible de l’animal. La deuxième construit "Pet: Luna (cat, 3 years)". La troisième demande explicitement la même description et la stocke sans l’afficher. Lorsqu’une ArrayList d’animaux est affichée, son affichage utilise la méthode toString() de chaque animal entre les crochets de la liste.

La conversion automatique explique pourquoi il est important de renvoyer du texte. L’appelant peut afficher, stocker ou concaténer le résultat. Une méthode qui ne fait qu’afficher ne peut pas fournir la chaîne dont tous ces appelants ont besoin.

Respecte l’en-tête de la méthode
DéclarationRésultat
public String toString()Fournit la description de l’objet
public String tostring()Déclare une méthode différente ; @Override détecte l’erreur
public String toString(int width)Déclare une surcharge ; l’affichage automatique ne l’appelle pas
public void toString()Échoue : elle entre en conflit avec la méthode existante qui renvoie une String

Utilise l’en-tête exact sans argument et inclus l’annotation. Une surcharge avec paramètres peut être une méthode distincte valide, mais l’affichage d’un objet ne fournit pas ces paramètres.

Formate les valeurs sans les modifier

Une horloge a besoin d’heures et de minutes à deux chiffres. Dans sa méthode toString() :

return String.format(java.util.Locale.US,
    "%02d:%02d", this.hours, this.minutes);

Pour 9 heures et 5 minutes, la chaîne est "09:05". Chaque %02d formate un entier sur au moins deux positions, en ajoutant un zéro initial si nécessaire. String.format(java.util.Locale.US, "%.2f", 7.5) renvoie "7.50". Fournir les paramètres régionaux rend la sortie avec point décimal indépendante des paramètres régionaux de formatage par défaut de l’ordinateur.

Garde une description assez courte pour être lue pendant le débogage. Elle peut révéler un état non initialisé : concaténer un champ de nom valant null à une chaîne produit le texte "null", ce qui te ramène à l’initialisation. La description devrait rendre compte de l’état courant : afficher deux fois l’objet ne devrait donc pas faire avancer une horloge ni fêter un anniversaire.

Points clés

  • Écris public String toString() sans paramètre et renvoie un texte lisible.
  • L’annotation @Override permet au compilateur de vérifier que la méthode remplace une méthode existante.
  • Afficher un objet et le concaténer à une chaîne utilisent automatiquement toString.
  • Ne modifie pas l’état dans toString et laisse l’appelant décider où va le texte.
  • String.format peut compléter des valeurs et utiliser des paramètres régionaux explicites pour obtenir une sortie prévisible.

5.2 D’une exigence à une classe testée

Commence par déterminer ce qu’un objet doit mémoriser, ce que les appelants peuvent lui demander de faire et quels états doivent être autorisés. Transforme ensuite chaque élément en champs, constructeurs et méthodes.

Tire la conception d’une description

« Un livre de bibliothèque a un titre, un auteur et un nombre de pages. Il peut être prêté et rendu. Il ne peut pas être prêté à nouveau tant qu’il est déjà en prêt. »

Utilise LibraryBook comme nom de classe. Stocke les trois valeurs descriptives et un état de prêt booléen. Le titre, l’auteur et le nombre de pages restent fixes : rends-les donc final. L’état du prêt change par des actions qui ont un sens. Un mutateur pour chaque champ est inutile.

Construis la classe complète
public class LibraryBook {
    private final String title;
    private final String author;
    private final int pages;
    private boolean lentOut;

    public LibraryBook(String title, String author, int pages) {
        this.title = title;
        this.author = author;
        this.pages = pages;
        this.lentOut = false;
    }

    public boolean isLentOut() {
        return this.lentOut;
    }

    public boolean lend() {
        if (this.lentOut) {
            return false;
        }
        this.lentOut = true;
        return true;
    }

    public void giveBack() {
        this.lentOut = false;
    }

    @Override
    public String toString() {
        String status = this.lentOut ? "lent out" : "available";
        return this.title + " by " + this.author + ", "
            + this.pages + " pages, " + status;
    }
}

Le constructeur rend le livre disponible. lend() vérifie l’état existant avant de le modifier ; renvoyer false lors d’un deuxième prêt préserve la règle. giveBack() rend le livre disponible. L’accesseur indique son état et toString() décrit le livre entier sans le modifier.

Écris les résultats attendus avant d’exécuter les appels

Dans la méthode main classique d’une classe Main distincte :

LibraryBook b = new LibraryBook("Night Train", "A. Rivera", 320);
System.out.println(b);        // Night Train by A. Rivera, 320 pages, available
System.out.println(b.lend()); // true
System.out.println(b.lend()); // false
b.giveBack();
System.out.println(b.lend()); // true

La deuxième tentative de prêt est essentielle : une méthode qui définit toujours l’indicateur et renvoie true réussirait le premier appel mais échouerait à cette vérification. Teste l’état ainsi que les valeurs de retour avec isLentOut(). Essaie aussi un deuxième livre pour vérifier que le prêt de l’un laisse l’autre disponible.

Teste les points où le comportement change

Couvre chaque constructeur et chaque méthode publique. Pour les vérifications d’intervalle, essaie les deux bornes et des valeurs juste à l’extérieur. Pour une horloge, vérifie le passage à l’heure suivante et le passage à minuit. Pour un mutateur qui rejette ou ignore une entrée invalide, vérifie qu’elle a l’effet annoncé sur l’ancien état. Écris d’abord le résultat attendu pour qu’une sortie inattendue ne devienne pas discrètement ta nouvelle attente.

Construis par petites étapes : les champs et le constructeur d’abord, puis une description lisible, puis une opération et ses vérifications à la fois. Enregistre les classes publiques ordinaires dans des fichiers de noms correspondants, compile-les ensemble et exécute la classe qui contient main. Séparer les opérations du modèle de l’affichage à l’écran permet à la même classe de servir dans différents programmes.

Points clés

  • Transforme les données à mémoriser en champs privés et les actions autorisées en méthodes.
  • Écris les règles de l’état avant d’implémenter les constructeurs et les modifications.
  • Utilise final pour les valeurs fixes propres à chaque objet et évite les mutateurs inutiles.
  • Teste les valeurs de retour et l’état obtenu, notamment avec des appels répétés et des objets distincts.
  • Vérifie les bornes et les entrées invalides ainsi que les valeurs ordinaires.
  • Construis et teste une partie utile à la fois.
  • Sépare le comportement du modèle du programme principal qui affiche les résultats.

Classes et objets en Java : exemples

5 Leçons Interactives

1

D’une classe à deux animaux

10 étapes
Crée des objets, repère leur état et suis les appels à travers des références distinctes et partagées.
  1. 1
    IntroductionUn type pour les éléments de ton programme

    Un programme sur les animaux de compagnie doit mémoriser ensemble un nom, une espèce et un âge. Une classe donne un type à ce groupe et propose des méthodes qui l’utilisent. Chaque objet est un animal créé à partir de cette définition.

    Suis la différence entre la définition et les animaux qu’elle produit. Puis suis l’état de deux objets représentant des animaux et vois pourquoi une variable supplémentaire ne signifie pas toujours un objet supplémentaire.

  2. 2
    AnalogieUn plan et ses instances

    Imagine une classe comme un plan de construction et ses objets comme les maisons construites à partir de ce plan. Le plan décrit ce que contient chaque maison, mais il n’est pas lui-même une maison.

    Une définition Pet peut décrire de nombreux animaux. Chacun possède des champs pour les mêmes types de données, mais l’un peut être un chat de trois ans et l’autre un chien de cinq ans. Définir les champs crée le plan ; la création d’objets fournit des instances concrètes.

  3. 3
    ExempleRepère l’état et le comportement

    Les champs name, species et age d’un animal stockent son état. Pour Luna, leurs valeurs sont "Luna", "cat" et 3.

    La méthode celebrateBirthday() définit un comportement. Son corps peut exécuter this.age++;, ce qui modifie l’âge de l’animal receveur. La méthode fait partie de la définition de la classe ; la valeur qu’elle modifie appartient à un animal précis.

  4. 4
    DéfiUne définition crée-t-elle un animal ?

    Un programmeur écrit une classe Pet avec trois champs et une méthode d’anniversaire. Aucune expression de création d’objet n’a été exécutée. Combien d’objets représentant des animaux cette définition a-t-elle créés ?

    ---reveal---

    Aucun. La classe définit un type, ainsi que son état et son comportement possibles. Les objets apparaissent lorsque le programme les crée, par exemple avec new Pet(...). Trois déclarations de champs décrivent trois données par animal, pas trois animaux.

  5. 5
    ExempleCrée le premier objet

    Lis Pet luna = new Pet("Luna", "cat", 3); par parties. Pet luna déclare une variable. new Pet(...) crée un animal et exécute le constructeur avec les trois arguments fournis.

    Le constructeur stocke les valeurs initiales. La référence produite par new est affectée à luna, ce qui permet au code suivant d’accéder à cet objet. Déclarer Pet luna; seul ne fournirait aucun objet sur lequel effectuer un appel.

  6. 6
    ExplicationAppelle une méthode sur son objet receveur

    Dans luna.celebrateBirthday(), l’expression avant le point désigne l’objet receveur. La méthode d’anniversaire s’exécute pour Luna et fait passer son âge de 3 à 4 ans.

    int age = luna.getAge(); récupère ensuite l’âge courant pour l’utiliser ailleurs. Pet.celebrateBirthday() ne peut pas choisir un animal : c’est une méthode d’instance et un nom de classe ne fournit aucun objet précis.

  7. 7
    ExempleCrée un deuxième animal

    Exécute maintenant Pet max = new Pet("Max", "dog", 5);. Une deuxième expression new crée un deuxième objet avec ses propres champs.

    Après un nouvel appel à luna.celebrateBirthday(), Luna a 5 ans et Max a toujours 5 ans. Leurs âges égaux ne font pas d’eux un même objet. Un anniversaire ultérieur de Luna ne modifie que son âge, car l’âge de Max se trouve dans les champs d’un autre objet.

  8. 8
    Point cléUne affectation peut partager un objet

    Pet other = luna; copie la référence vers Luna. Cette instruction n’appelle pas de constructeur et ne copie pas ses champs dans un autre animal.

    Les noms other et luna donnent maintenant accès au même objet. Appeler other.celebrateBirthday() fait passer l’âge de cet animal de 5 à 6 ans et luna.getAge() indique aussi 6. Compte les créations d’objets séparément des déclarations de variables.

  9. 9
    DéfiSuis une référence partagée et un animal distinct

    Deux animaux distincts ont initialement 1 an pour a et 8 ans pour b. Le code exécute Pet c = a; c.celebrateBirthday(); b.celebrateBirthday();. Quels âges a et b indiquent-ils ?

    ---reveal---

    Ils indiquent 2 et 9. c partage l’objet de a, donc son appel augmente l’âge de cet animal. L’appel par b augmente l’âge de l’animal distinct. La classe fournit le même comportement d’anniversaire aux deux, mais chaque appel a son propre objet receveur.

  10. 10
    RécapitulatifLis attentivement les créations et les appels

    Distingue trois rôles : la classe définit le type, chaque objet contient son propre état d’instance et une variable de référence donne accès à un objet.

    Lorsque tu lis le code, repère chaque new, fais correspondre ses arguments au constructeur et identifie l’objet receveur avant de suivre un appel de méthode. Une simple affectation de référence ajoute un moyen d’accéder à un objet existant. Un deuxième new crée un objet distinct avec son propre état.

2

Construis correctement l’état initial

14 étapes
Choisis les champs, suis les affectations du constructeur et utilise les surcharges sans créer d’objets supplémentaires.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionDonne des données utiles à chaque nouvel objet
  2. 2
    ExplicationChoisis un état durable
  3. 3
    ExplicationDistingue les valeurs par défaut des valeurs utiles
  4. 4
    DéfiChoisis un champ ou une variable locale
  5. 5
    ExplicationLis l’en-tête du constructeur
  6. 6
    ExempleTransfère les paramètres dans les champs
  7. 7
    ConseilUne affectation valide qui ne stocke rien
  8. 8
    DéfiTrouve le champ inchangé
  9. 9
    LienCrée aussi les objets internes
  10. 10
    ExemplePropose une façon utile de construire l’objet par défaut
  11. 11
    ExplicationSuis un objet dans la chaîne
  12. 12
    DéfiDiagnostique une expression new trompeuse
  13. 13
    DéfiCombine un champ fixe avec une surcharge
  14. 14
    RécapitulatifVérifie chaque chemin vers un objet terminé
3

Suis les modifications d’état et l’état partagé

13 étapes
Étudie un rectangle et une horloge, puis distingue le comportement d’instance des membres statiques.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionSuis ce que chaque appel modifie
  2. 2
    ExplicationRenvoie une valeur à l’appelant
  3. 3
    ExempleModifie les dimensions stockées à l’aide d’un facteur
  4. 4
    DéfiVérifie le résultat renvoyé après une modification
  5. 5
    ExempleAvance jusqu’au passage à minuit
  6. 6
    ConseilCorrige une remise à zéro qui ne modifie pas l’état
  7. 7
    Point cléPrévois chaque retour normal
  8. 8
    ExplicationDistingue deux comptes d’un compteur partagé
  9. 9
    ExempleFournis un objet dans le code statique
  10. 10
    LienReconnais une constante
  11. 11
    DéfiSuis les deux types d’état
  12. 12
    DéfiTrouve pourquoi des objets distincts changent ensemble
  13. 13
    RécapitulatifAssocie chaque opération à son propriétaire
4

Protège chaque voie de modification de l’état

14 étapes
Utilise des méthodes d’accès, la validation et des copies de listes pour que l’objet respecte ses règles.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionRends la classe responsable de ses règles
  2. 2
    ExplicationMasque le champ derrière une opération
  3. 3
    ConseilChoisis l’accès utile le plus restrictif
  4. 4
    DéfiDétermine où l’accès privé fonctionne
  5. 5
    ExempleRenvoie une information avec un accesseur
  6. 6
    LienPropose des actions adaptées à l’objet
  7. 7
    DéfiPermets la lecture sans autoriser le remplacement
  8. 8
    ExplicationChoisis comment traiter une entrée invalide
  9. 9
    ExempleSuis l’écrêtage à la borne supérieure
  10. 10
    ExempleVérifie l’état initial
  11. 11
    DéfiSuis le traitement qui ignore la valeur au lieu de l’écrêter
  12. 12
    Point cléUne liste privée peut tout de même être exposée
  13. 13
    DéfiFerme les deux voies non vérifiées
  14. 14
    RécapitulatifExamine l’interface publique
5

Construis et teste une classe utile

12 étapes
Écris une description lisible, implémente une règle de prêt et teste une classe complète de livre de bibliothèque.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionTransforme une exigence en comportement visible
  2. 2
    ExplicationUtilise l’en-tête exact de description
  3. 3
    ExempleRenvoie l’état courant sous forme de texte
  4. 4
    ConseilFormate une horloge sans la modifier
  5. 5
    DéfiCorrige l’affichage automatique
  6. 6
    ExempleChoisis les champs à partir de l’exigence
  7. 7
    ExempleDéfinis l’état initial
  8. 8
    ExempleApplique la règle avant la modification
  9. 9
    DéfiPrévois une séquence avant de l’exécuter
  10. 10
    LienTeste les cas qu’une exécution simple ne révèle pas
  11. 11
    DéfiDistingue la description de la modification
  12. 12
    RécapitulatifConstruis avec une garantie publique vérifiable

Classes et objets en Java : QCM

40 Questions Pratiques en 4 séries

Série 1 : Crée des objets et lis leur état10 Questions Pratiques

Question 1 sur 10

Un programme de livraison utilise une classe Parcel pour créer plusieurs colis. Comment appelle-t-on un colis créé pendant l’exécution du programme ?
  1. Une définition de Parcel.
  2. Une instance de Parcel.
  3. Une méthode de Parcel.
  4. Un paramètre de Parcel.
Afficher la réponseMasquer la réponse
Réponse : B
Une instance est un objet créé à partir d’une classe : chaque colis est donc une instance de Parcel. La définition de la classe décrit les données et les opérations de tous ces objets ; elle n’est pas un autre nom pour un colis particulier. Une méthode est une opération que l’objet peut effectuer.

Question 2 sur 10

Un objet Bell est stocké dans bell, et ring() est une méthode d’instance. Comment le programme doit-il faire sonner cette cloche ?
  1. Bell.ring(bell);
  2. ring(bell);
  3. new bell.ring();
  4. bell.ring();
Afficher la réponseMasquer la réponse
Réponse : D
La notation pointée appelle ring() sur l’objet désigné par bell. La variable avant le point fournit l’objet receveur dont une méthode d’instance a besoin. Bell.ring() désigne la classe : cet appel ne peut donc pas sélectionner cette cloche pour une méthode d’instance.

Question 3 sur 10

Une classe déclare private int attempts; sans initialiseur ni affectation dans le constructeur. Quelle valeur un nouvel objet stocke-t-il dans ce champ ?
  1. 0
  2. 1
  3. null
  4. Aucune valeur ; la compilation échoue.
Afficher la réponseMasquer la réponse
Réponse : A
Un champ d’instance int reçoit la valeur par défaut 0 avant toute initialisation explicite. La règle qui impose une affectation avant la lecture d’une variable locale non initialisée ne s’applique pas aux champs. null est la valeur par défaut des champs dont le type est une classe, pas d’un champ int.

Question 4 sur 10

Après new Badge("Visitor"), getText() renvoie null. Le champ est private String text;, l’accesseur le renvoie et le corps du constructeur est text = text;. Comment le constructeur doit-il stocker son paramètre text ?
  1. text = this.text;
  2. String text = "Visitor";
  3. this.text = text;
  4. this.text = this.text;
Afficher la réponseMasquer la réponse
Réponse : C
Le paramètre masque le champ lorsque son nom seul est utilisé. this.text = text; écrit la valeur fournie dans l’objet courant. Inverser l’affectation lit au contraire le champ encore à null dans le paramètre, et affecter le champ à lui-même le laisse aussi sans valeur définie.

Question 5 sur 10

Une classe possède Ticket() { this(4); } et Ticket(int zones) { this.zones = zones + 1; }. Quelle valeur new Ticket() stocke-t-il dans zones ?
  1. 0
  2. 4
  3. 5
  4. 8
Afficher la réponseMasquer la réponse
Réponse : C
Le constructeur sans argument délègue avec l’argument 4 sur le même objet. Le constructeur le plus complet ajoute 1 et stocke 5. Le 4 fourni est une valeur de paramètre pendant l’initialisation ; ce n’est pas la valeur finale du champ, car le constructeur effectue le calcul supplémentaire.

Question 6 sur 10

Une classe MinuteClock stocke les heures de 0 à 23 et les minutes de 0 à 59. advance() ajoute une minute en gérant le passage à l’heure suivante et à minuit. isMidnight() vérifie si l’heure est 00 h 00. En partant de 23 h 57, exécute advance(); advance(); advance(); if (isMidnight()) { advance(); } advance();. Quelle est l’heure finale ?
  1. 00:01
  2. 00:02
  3. 00:00
  4. 23:59
Afficher la réponseMasquer la réponse
Réponse : B
Les trois premiers appels atteignent 23 h 58, puis 23 h 59, puis 00 h 00. La condition est alors vraie, donc son appel fait avancer l’horloge à 00 h 01, et le dernier appel atteint 00 h 02. S’arrêter à 00 h 01 oublie l’appel inconditionnel après le bloc conditionnel.

Question 7 sur 10

Chaque Lamp doit mémoriser son propre état allumé ou éteint. Comment cet état doit-il être déclaré ?
  1. private boolean on;
  2. private static boolean on;
  3. public static final boolean ON = false;
  4. Une variable locale boolean on dans switchOn().
Afficher la réponseMasquer la réponse
Réponse : A
Un champ d’instance conserve une valeur distincte pour chaque lampe et la mémorise entre les appels. Rendre le champ statique ferait partager une seule valeur d’état à toutes les lampes. Une variable locale dans la méthode d’allumage ne fournirait pas l’état durable propre à chaque lampe dont la conception a besoin.

Question 8 sur 10

Un champ de Bin est écrit int capacity; sans modificateur d’accès. Quel est son accès ?
  1. Un accès privé.
  2. Un accès protégé.
  3. Un accès public.
  4. Un accès de paquetage.
Afficher la réponseMasquer la réponse
Réponse : D
Un membre sans modificateur d’accès possède un accès de paquetage : les autres classes du même paquetage peuvent donc l’utiliser. Il ne devient pas privé simplement parce que public a été omis. Pour que l’accès au champ passe par les méthodes de sa classe, déclare-le explicitement avec private.

Question 9 sur 10

Une classe Session possède private boolean active;. Les appelants doivent pouvoir le consulter, mais ne peuvent le modifier que par start() et stop(). Quel accesseur convient à cette conception ?
  1. public void isActive() { System.out.println(this.active); }
  2. public boolean setActive(boolean value) { return value; }
  3. public void setActive(boolean value) { this.active = value; }
  4. public boolean isActive() { return this.active; }
Afficher la réponseMasquer la réponse
Réponse : D
L’accesseur booléen renvoie l’indicateur courant sans donner aux appelants un autre moyen de le modifier. L’affichage depuis une méthode void ne fournit pas de valeur à une condition de l’appelant. Un mutateur public ajouterait une voie de modification en plus des deux actions autorisées par la conception.

Question 10 sur 10

Un objet définit public String toString() { return "Ready"; }. Quel texte est produit par System.out.println("State: " + object); ?
  1. Ready
  2. State: Ready
  3. State: Object@Ready
  4. State: toString()
Afficher la réponseMasquer la réponse
Réponse : B
La concaténation de chaînes utilise la description textuelle renvoyée par l’objet : le libellé et "Ready" se combinent donc en "State: Ready". Définir une méthode toString() personnalisée sans argument remplace la description intégrée contenant la classe et le code de hachage ; Java n’ajoute pas ce texte intégré en préfixe.
Série 2 : Vérifie l’initialisation et les modifications contrôlées10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Une classe Locker possède un champ occupied et une méthode release(). Quelle partie de cette classe décrit un comportement ?
  1. Le champ occupied.
  2. La valeur actuelle true.
  3. La méthode release.
  4. Le type de variable Locker.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une classe Panel stocke une largeur et une hauteur. Sa largeur peut changer et getArea() doit toujours indiquer l’aire actuelle. Comment l’aire doit-elle être représentée ?
  1. Calculer largeur fois hauteur dans getArea.
  2. Stocker l’aire du constructeur dans un champ final.
  3. Stocker l’aire une fois dans un champ statique partagé.
  4. Garder la dernière aire dans une variable locale du constructeur.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Une classe ne déclare que public Sensor(int channel). Un appelant utilise new Sensor(). Pourquoi cet appel ne se compile-t-il pas ?
  1. Le paramètre doit être nommé sensor.
  2. Chaque classe doit déclarer un constructeur void.
  3. Java exige que channel soit un champ statique.
  4. Aucun constructeur sans argument n’est disponible.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Un appareil de mesure stocke private int reading = 9;. Sa méthode est public void reset() { int reading = 0; }. Que renvoie un accesseur qui renvoie this.reading après reset() ?
  1. 0
  2. 9
  3. null
  4. Une erreur de compilation pour retour manquant.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une méthode convertit un nombre de minutes fourni en heures en utilisant uniquement son paramètre. Elle n’a besoin d’aucun champ d’objet. Quel type de méthode peut remplir ce rôle ?
  1. Un champ d’instance.
  2. Une méthode statique.
  3. Une surcharge de constructeur.
  4. Une variable locale finale.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Une horloge remplace ses champs distincts pour les heures et les minutes par un seul champ minutesSinceMidnight, tandis que ses accesseurs renvoient toujours les mêmes valeurs. Pourquoi les appelants peuvent-ils conserver leurs appels existants aux accesseurs ?
  1. Les champs privés deviennent publics pour les appelants.
  2. Le compilateur remplace les appels aux accesseurs par des champs.
  3. Chaque appelant reçoit une copie des anciens champs.
  4. Le comportement public reste cohérent.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Une jauge commence à 16. Son mutateur écrête les entrées dans l’intervalle de 10 à 20 inclus. Après setValue(25) puis setValue(8), quelles sont les valeurs stockées après chaque appel ?
  1. 20, puis 10.
  2. 16, puis 16.
  3. 25, puis 8.
  4. 20, puis 20.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Un Group doit contenir au maximum quatre noms. addName impose cette limite, mais Group(ArrayList<String> names) stocke directement la liste fournie et getNames() renvoie la liste interne. Quelle conception préserve la limite face aux modifications des appelants ?
  1. Valider et copier la liste fournie ; renvoyer une copie.
  2. Copier seulement la liste fournie ; renvoyer la liste interne.
  3. Valider seulement la liste fournie ; renvoyer la liste interne.
  4. Copier seulement au retour ; stocker toute liste fournie.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Quel type de retour la méthode sans argument toString() doit-elle utiliser ?
  1. void
  2. Object[]
  3. String
  4. boolean
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Un laissez-passer est initialement inutilisé. use() renvoie false s’il a déjà été utilisé ; sinon, elle active l’indicateur et renvoie true. reset() désactive l’indicateur. toString() ne fait que l’indiquer. Que renvoient les appels à use dans use(); println(pass); use(); reset(); use(); use(); ?
  1. true, true, true, false
  2. true, false, false, false
  3. true, false, true, true
  4. true, false, true, false
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 3 : Suis l’état des objets dans des séquences plus longues10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Un Marker possède un nom et setName. Exécute Marker a = new Marker("One"); Marker b = a; a = new Marker("Two"); b.setName("Three");. Que renvoient a.getName() et b.getName() ?
  1. "Three" et "Three".
  2. "Three" et "Two".
  3. "Two" et "One".
  4. "Two" et "Three".
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une classe déclare private int level = 6;. Son constructeur est public Beacon(int level) { this.level = level + 2; }. Que stocke new Beacon(3) ?
  1. 6
  2. 5
  3. 3
  4. 8
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Une classe possède déjà public Tag(String text). Quel constructeur supplémentaire fournit une surcharge distincte ?
  1. public Tag(String text, int count)
  2. public Tag(String label)
  3. public Tag(String value)
  4. public Tag(String name)
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Un rectangle a une largeur de 2,0 cm et une hauteur de 5,0 cm. scale(k) multiplie les deux dimensions par k ; area() renvoie leur produit. Exécute scale(2); double saved = area(); scale(0.5);. Que valent saved et le résultat final de area() ?
  1. 20,0 et 10,0 centimètres carrés.
  2. 40,0 et 20,0 centimètres carrés.
  3. 40,0 et 10,0 centimètres carrés.
  4. 10,0 et 10,0 centimètres carrés.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une classe Dial nouvellement utilisée possède un champ d’instance value et un champ statique created, tous deux initialement à 0. Chaque constructeur incrémente created une fois ; turn() n’incrémente que la valeur de son objet receveur. Exécute Dial a = new Dial(); Dial b = a; b.turn(); b = new Dial(); b.turn(); b.turn();. Que valent a.value, b.value et created ?
  1. 1, 2 et 2.
  2. 2, 2 et 2.
  3. 1, 3 et 2.
  4. 1, 2 et 3.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Un accesseur doit renvoyer un libellé stocké dans private String label;. Quelle implémentation fournit cette valeur à son appelant ?
  1. public void getLabel() { System.out.println(this.label); }
  2. public void getLabel(String label) { this.label = label; }
  3. public String getLabel() { return "label"; }
  4. public String getLabel() { return this.label; }
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Un niveau est écrêté dans l’intervalle de 0 à 10 inclus par setLevel. Le constructeur appelle ce mutateur et raise() appelle setLevel(this.level + 1). En partant de new Level(13), exécute raise(); setLevel(-2); raise(); raise();. Quel est le niveau final ?
  1. 10
  2. 2
  3. 1
  4. 0
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Dans la description d’une horloge, quelle chaîne String.format(java.util.Locale.US, "%02d:%02d", 4, 7) renvoie-t-elle ?
  1. "4:7"
  2. "40:70"
  3. "04:07"
  4. "04.07"
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Un Seat doit refuser une deuxième réservation tant que la première n’est pas annulée. Un test ne vérifie actuellement que le premier appel réussi à reserve(). Quel appel suivant vérifie le mieux la règle de refus ?
  1. Appeler reserve à nouveau sans annuler.
  2. Annuler d’abord, puis rappeler reserve.
  3. Créer un autre siège et le réserver.
  4. Annuler la réservation sans réserver à nouveau.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Un thermostat accepte des températures cibles de 6 °C à 28 °C inclus. Quelle paire d’entrées teste les valeurs juste à l’extérieur des deux bornes ?
  1. 6 °C et 28 °C.
  2. 5 °C et 29 °C.
  3. 7 °C et 27 °C.
  4. 17 °C et 18 °C.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 4 : Diagnostique les conceptions et combine les règles10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Un programme gère plusieurs pompes. Chacune possède un identifiant et une vitesse actuelle différents, et chacune peut démarrer ou s’arrêter. Comment une classe Pump devrait-elle représenter cela ?
  1. Des champs statiques pour l’identifiant et la vitesse ; des méthodes pour démarrer et arrêter.
  2. Des champs d’instance pour l’identifiant et la vitesse ; des méthodes pour démarrer et arrêter.
  3. Des champs d’instance pour démarrer et arrêter ; des identifiants locaux à chaque appel.
  4. Des vitesses locales dans les méthodes de démarrage et d’arrêt ; une constante d’identifiant partagée.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Un Token possède une valeur numérique et addOne() l’augmente. Exécute Token a = new Token(2); Token b = a; b.addOne(); Token c = new Token(7); a = c; a.addOne(); b.addOne();. Quelles valeurs a, b et c indiquent-ils ?
  1. 4, 4 et 8.
  2. 8, 8 et 8.
  3. 8, 4 et 8.
  4. 8, 3 et 7.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Un objet de suivi doit conserver un total entre les appels. Sa méthode add(int amount) déclare actuellement int total = amount; dans son corps. Quelle modification du stockage rend l’accumulation possible ?
  1. Déclarer un champ d’instance total et le mettre à jour dans add.
  2. Déclarer à nouveau le même total local dans l’accesseur.
  3. Déclarer amount comme variable locale dans le constructeur uniquement.
  4. Déclarer un total local final dans chaque appel à add.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Une classe Bucket déclare private int capacity = 2; et une liste d’instance vide items. Son constructeur est Bucket(int capacity) { capacity = capacity; }. add renvoie false sans ajouter d’élément lorsque la taille de la liste est au moins égale à la capacité stockée ; sinon, elle ajoute l’élément et renvoie true. snapshot() renvoie new ArrayList<>(this.items).

Exécute Bucket b = new Bucket(4); b.add("A"); ArrayList<String> view = b.snapshot(); view.add("B");. Appelle ensuite b.add("C") et b.add("D"). Que renvoient ces deux derniers appels et combien d’éléments b contient-il finalement ?

  1. true, true ; 3 éléments.
  2. false, false ; 2 éléments.
  3. true, false ; 3 éléments.
  4. true, false ; 2 éléments.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une classe Route possède un champ final code et un champ statique created, initialement à 0. Ses constructeurs sont Route() { this("local"); created++; } et Route(String code) { this.code = code; created++; }. Après un appel à chaque constructeur, created devrait compter deux objets. Quelle correction donne le bon compte ?
  1. Supprimer created++ du constructeur avec String.
  2. Remplacer this("local") par new Route("local").
  3. Garder les deux incrémentations et faire de created un champ d’instance.
  4. Supprimer created++ du constructeur sans argument.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Un minuteur démarre à 22 h 59. advance() ajoute une minute et revient au début du cycle de 24 heures. getHour() lit l’heure courante. Exécute int h = getHour(); advance(); if (getHour() != h) { advance(); } advance();. Que valent h et l’heure finale ?
  1. 23 et 23 h 02.
  2. 22 et 23 h 01.
  3. 22 et 23 h 02.
  4. 23 et 23 h 01.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Une méthode auxiliaire ne doit pouvoir être appelée que par le code situé dans sa propre classe de premier niveau. Quel modificateur d’accès convient ?
  1. public
  2. private
  3. protected
  4. Aucun modificateur.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Un rectangle change de dimensions grâce à scale. Son accesseur renvoie this.width * this.height et il n’existe aucun champ d’aire. Pourquoi cette conception de l’accesseur est-elle valide ?
  1. Il renvoie une information actuelle sans exposer le stockage.
  2. Chaque accesseur doit renvoyer un champ de même nom exact.
  3. La méthode crée un champ d’aire à chaque appel.
  4. Le produit devient une constante après le premier appel.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Un Album est limité à trois légendes. Son constructeur rejette plus de trois légendes et stocke new ArrayList<>(captions). getCaptions() renvoie une autre copie ; addCaption refuse les ajouts lorsque la limite est atteinte. Un appelant fournit deux légendes, en ajoute une troisième à la liste originale, ajoute une légende au résultat d’un accesseur, puis appelle une fois addCaption. Combien de légendes l’Album contient-il ?
  1. 2
  2. 4
  3. 5
  4. 3
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Une Door doit refuser open() lorsqu’elle est verrouillée. Une porte nouvellement créée est fermée et déverrouillée. lock() ne réussit que si la porte est fermée ; unlock() la déverrouille. Quelle séquence de test vérifie le refus lorsque la porte est verrouillée, puis une ouverture réussie après son déverrouillage ?
  1. lock ; open → false ; unlock ; open → true.
  2. open → true ; lock ; open → false ; unlock.
  3. lock ; unlock ; open → true ; open → false.
  4. open → true ; unlock ; lock ; open → false.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Tu bloques sur ton propre exercice ? Aide aux Devoirs

Mots-Clés

59 Mots-Clés, chacun avec sa définition

A

Accès de paquetage
L’accès de paquetage permet aux classes d’un même paquetage d’utiliser une déclaration ; il est obtenu en omettant le modificateur d’accès.
L’accès de paquetage sur int count; permet à une autre classe du même paquetage sans nom de lire ou de modifier le champ.
Accesseur
Un accesseur est une méthode qui renvoie une information sur un objet sans le modifier, souvent avec un nom commençant par get.
L’accesseur getArea() peut calculer la largeur multipliée par la hauteur même lorsque la classe ne stocke aucun champ d’aire distinct.
Appel récursif de constructeur
Un appel récursif de constructeur est une chaîne de constructeurs interdite qui finit par appeler un constructeur déjà présent dans cette chaîne.
Java signale un appel récursif de constructeur lorsque Box() et Box(int) délèguent l’un à l’autre.
Argument
Un argument est une valeur fournie lors d’un appel de méthode ou de constructeur, associée à un paramètre selon sa place et son type compatible.
Dans new Clock(9, 5), les arguments 9 et 5 fournissent l’heure et la minute de la nouvelle horloge.

C

Chaînage de constructeurs
Le chaînage de constructeurs exécute un autre constructeur de la même classe sur le même objet au moyen d’un appel this(...).
Le chaînage de constructeurs permet à un animal nouveau-né d’utiliser this(name, species, 0) pour réutiliser l’initialisation avec un âge par défaut.
Champ final
Un champ final ne peut recevoir une valeur qu’une fois : il est donc utile pour les données propres à un objet qui ne doivent pas être remplacées après l’initialisation.
Le titre d’un livre peut être un champ final initialisé dans son constructeur, sans mutateur proposé aux appelants.
Champ statique
Un champ statique est une variable unique de la classe partagée par toutes les instances : sa valeur n’appartient donc pas à un objet particulier.
Un champ statique nommé created peut augmenter chaque fois que le constructeur initialise une nouvelle instance de la classe.
Classe
Une classe définit un type Java en décrivant les données que ses objets contiennent et les méthodes qui définissent leur comportement.
Une classe Pet rassemble un nom, une espèce et un âge avec des opérations comme celebrateBirthday().
Comportement
Le comportement d’un objet est l’ensemble des opérations que ses méthodes fournissent pour lire son état, effectuer des calculs à partir de celui-ci ou le modifier.
Un livre propose les comportements lend() et giveBack() pour que les appelants puissent gérer son état de prêt.
Conception de classe
La conception de classe consiste à choisir l’état, les chemins de construction, les opérations et les règles qui permettent à une classe de représenter un type de chose utile.
La conception de classe transforme une description de livre de bibliothèque en champs d’identification, un indicateur de prêt et des opérations qui font respecter les règles de prêt.
Constante
Une constante est une valeur fixe généralement fournie par un champ static final, souvent public et nommé en UPPER_SNAKE_CASE.
Une constante MAX_CELSIUS fournit la même limite supérieure de température à la classe et à ses appelants.
Constructeur
Un constructeur est une déclaration portant le nom de la classe, sans type de retour, qui initialise un objet lors de sa création.
Le constructeur de Pet copie le nom, l’espèce et l’âge fournis dans les champs du nouvel animal.
Constructeur par défaut
Un constructeur par défaut est le constructeur sans argument que Java fournit lorsqu’une classe ne déclare aucun constructeur.
Ajouter un constructeur à trois arguments supprime le constructeur par défaut : new Pet() nécessite donc une surcharge explicite.
Constructeur sans argument
Un constructeur sans argument n’accepte aucune valeur en entrée ; il peut être déclaré explicitement ou fourni par Java comme constructeur par défaut.
Un constructeur explicite sans argument Clock() peut déléguer avec this(0, 0) pour démarrer l’horloge à minuit.
Contexte statique
Un contexte statique est du code sans instance courante, comme le corps d’une méthode statique, où l’accès aux membres d’instance par leur seul nom n’est pas disponible.
Dans un contexte statique, un champ d’âge nommé seul n’a pas d’animal courant ; pet.getAge() fournit au contraire un objet précis.
Copie défensive
Une copie défensive est un objet de données distinct, renvoyé ou stocké pour empêcher une autre partie du programme de modifier directement les données internes.
Une copie défensive créée par new ArrayList<>(this.tracks) empêche les modifications extérieures de la liste d’atteindre la liste interne.

D

Développement incrémental
Le développement incrémental consiste à construire et à vérifier une partie utile à la fois, ce qui facilite la localisation des erreurs avant l’ajout de code supplémentaire.
Avec le développement incrémental, vérifie d’abord le constructeur, puis ajoute et teste une opération à la fois.
Durée de vie
La durée de vie d’une variable est la période d’exécution pendant laquelle son stockage existe ; un champ d’instance dure aussi longtemps que son objet.
La durée de vie d’un champ de compte s’étend entre les appels d’incrémentation, tandis qu’une variable locale temporaire n’existe que pendant son appel.

É

Écrêtage
L’écrêtage remplace une valeur située hors d’un intervalle autorisé par la borne la plus proche, tout en conservant les valeurs déjà comprises dans l’intervalle.
Avec un écrêtage entre 5 °C et 30 °C, une demande de 34 °C stocke 30 °C, tandis qu’une demande de 18 °C stocke 18 °C.
État
L’état d’un objet est l’ensemble actuel des valeurs stockées dans ses champs d’instance, comme l’heure et la minute d’une horloge.
Après qu’une horloge a avancé depuis 08 h 59, son état contient l’heure 9 et la minute 0, prêt pour l’appel suivant.

E

Encapsulation
L’encapsulation regroupe l’état d’un objet et les opérations qui le contrôlent, et masque les données internes derrière une interface choisie.
L’encapsulation dans Pet associe un champ d’âge privé à des méthodes de vérification qui refusent les modifications invalides.

I

IllegalArgumentException
Une IllegalArgumentException est une exception qu’une méthode ou un constructeur peut lever pour rejeter un argument qui ne respecte pas ses règles d’entrée.
Lever IllegalArgumentException pour une capacité négative empêche la construction de renvoyer un objet invalide.
Initialisation
L’initialisation donne à une variable sa première valeur ; l’initialisation d’un objet établit les champs nécessaires à un état initial utilisable.
L’initialisation d’une liste dans un constructeur de liste de lecture utilise new ArrayList<>() pour permettre l’ajout ultérieur d’éléments.
Instance
Une instance est un objet créé à partir d’une classe particulière ; le terme désigne la relation entre cet objet et son type.
Un animal nommé Luna et un animal nommé Max sont deux instances de Pet lorsque chacun est créé séparément.
Interface publique
L’interface publique d’une classe est l’ensemble des opérations et des valeurs publiques disponibles pour les appelants qui peuvent accéder à la classe.
L’interface publique d’un livre peut proposer lend(), giveBack() et isLentOut() tandis que son indicateur de prêt reste privé.
Invariant
Un invariant est une règle sur l’état qui doit être vraie après la construction et après chaque opération publique sur un objet.
L’invariant d’un thermostat maintient sa température cible dans l’intervalle autorisé même lorsqu’un appelant demande 40 °C.

M

Masquage
Le masquage se produit lorsqu’une déclaration plus proche, comme un paramètre, masque le nom simple d’un champ dans une partie du code.
Le masquage par un paramètre rend this.age = age; utile : le côté gauche désigne le champ et le côté droit la valeur fournie.
Masquage de l’information
Le masquage de l’information fait dépendre les appelants des opérations disponibles d’un objet plutôt que des détails de son stockage interne.
Le masquage de l’information permet à une horloge de modifier ses champs tout en gardant getHours() cohérente pour les appelants existants.
Méthode d’action
Une méthode d’action nomme une opération qui a un sens et que l’objet peut effectuer, en contrôlant souvent une modification plus précisément qu’un simple mutateur.
La méthode d’action lend() vérifie l’état actuel du prêt, refuse un nouveau prêt et indique si le prêt a réussi.
Méthode d’instance
Une méthode d’instance est une méthode non statique qui s’exécute pour un objet précis et peut utiliser les champs d’instance de cet objet.
scale est une méthode d’instance : a.scale(2) modifie le rectangle a tandis qu’un rectangle distinct reste inchangé.
Méthode statique
Une méthode statique appartient à une classe et n’a pas d’objet courant ; elle a besoin d’une référence vers un objet pour utiliser des membres d’instance.
Une méthode statique comme main peut créer Counter c, puis appeler c.increment() par cette référence.
Modificateur d’accès
Un modificateur d’accès est un mot-clé Java comme private, protected ou public qui contrôle l’accès à une déclaration.
Le modificateur d’accès private rend une méthode auxiliaire disponible dans sa classe sans l’exposer aux autres classes.
Mutateur
Un mutateur est une méthode qui accepte une nouvelle valeur pour une partie de l’état d’un objet et peut vérifier cette valeur avant de la stocker.
Le mutateur setAge(int age) peut ignorer les entrées négatives afin que l’âge stocké reste dans son intervalle autorisé.

N

new
Le mot-clé Java new commence une expression de création d’objet qui exécute un constructeur et produit une référence vers l’objet.
new Pet("Luna", "cat", 3) crée un animal et fournit trois arguments pour son état initial.
Notation pointée
La notation pointée désigne un membre par l’intermédiaire d’un objet receveur, par exemple une référence vers un objet suivie d’un point et d’un appel de méthode.
La notation pointée dans luna.getAge() indique à Java que l’animal désigné par luna doit fournir son âge.
null
La valeur Java null signifie qu’une référence ne donne accès à aucun objet ; les champs dont le type est une classe la reçoivent sauf s’ils sont initialisés autrement.
Appeler add sur un champ de type liste qui vaut encore null échoue, car aucun objet liste n’a été créé.

O

Objet
Un objet est une instance d’une classe qui existe pendant l’exécution d’un programme et possède ses propres valeurs actuelles de champs d’instance.
Deux objets représentant des animaux, créés avec des expressions new distinctes, peuvent avoir des âges différents tout en suivant une même définition de classe.
Objet receveur
L’objet receveur est l’objet sur lequel une méthode d’instance est appelée, désigné par l’expression avant le point dans un appel.
Dans book.lend(), l’objet receveur est le livre désigné par book, dont la méthode vérifie l’indicateur de prêt.

P

Paramètre
Un paramètre est une donnée d’entrée nommée, déclarée dans l’en-tête d’une méthode ou d’un constructeur, qui reçoit un argument à chaque appel.
Le paramètre age d’un constructeur d’animal reçoit 3 lorsque l’appel fournit 3 à cette place.
Portée
La portée d’une variable est la région du texte du programme où son nom peut être utilisé pour désigner cette variable.
La portée d’une variable locale déclarée dans un bloc if s’arrête à ce bloc : le code suivant ne peut donc pas utiliser son nom.
private
Le modificateur private limite l’accès à un membre au code situé dans sa classe, obligeant les appelants de classes de premier niveau distinctes à passer par l’interface publique.
Un champ d’âge privé fait échouer pet.age = -1; dans une classe Main distincte et nécessite un appel de méthode contrôlé.
Propriété en lecture seule
Une propriété en lecture seule est une information exposée à la lecture aux appelants sans leur fournir d’opération qui la remplace directement.
Un titre fixe est une propriété en lecture seule lorsque les appelants disposent de getTitle() mais d’aucune opération pour remplacer le titre.
protected
Le modificateur protected autorise l’accès depuis le même paquetage et un accès restreint depuis le code des sous-classes extérieures à ce paquetage.
Une méthode auxiliaire protégée peut être appelée par une autre classe de son paquetage même lorsque cette classe n’est pas une sous-classe.
public
Le modificateur public autorise l’accès à un membre partout où le type qui le déclare est accessible, afin que les appelants puissent utiliser l’opération exposée.
Une méthode lend() publique permet à Main de demander un prêt tandis que le champ privé d’état du livre reste masqué.

R

Référence
Une référence est une valeur qui désigne un objet et permet à une variable ou à une expression d’y accéder lorsque nécessaire.
Après Pet other = luna;, les deux variables contiennent des références vers le même animal, et chacune peut donc y accéder.
Résultat attendu
Un résultat attendu est la valeur de retour, la sortie ou l’état prévu à partir d’une exigence avant l’exécution d’un test.
Le résultat attendu d’un deuxième lend() sur un livre emprunté est false, avec un indicateur de prêt inchangé.

S

String.format
La méthode String.format construit du texte à partir d’une chaîne de format et de valeurs, en prenant notamment en charge des largeurs fixes et des décimales.
String.format avec java.util.Locale.US et "%.2f" formate 7,5 sous la forme "7.50" quels que soient les paramètres régionaux par défaut.
Surcharge de constructeurs
La surcharge de constructeurs consiste à déclarer plusieurs constructeurs pour une classe avec des listes de paramètres différentes, adaptées à différentes données de création.
La surcharge de constructeurs permet à une horloge d’accepter des heures et des minutes ou de démarrer à minuit sans argument.

T

Test aux limites
Un test aux limites vérifie le comportement à une borne autorisée ou près de celle-ci, là où une condition détermine si une opération doit réussir.
Un test aux limites d’un mutateur de température cible essaie une borne autorisée et une valeur juste à l’extérieur pour vérifier la comparaison.
this
Le mot-clé this désigne l’objet courant dans le code d’instance et distingue ses champs des paramètres de même nom.
Dans le mutateur d’un animal, this.name = name; écrit la nouvelle valeur fournie dans le champ de cet animal précis.
toString
La méthode toString() renvoie la représentation textuelle d’un objet, ce qui permet à l’affichage et à la concaténation de chaînes de montrer des détails lisibles.
La méthode toString d’une horloge renvoie "09:05", donc afficher l’horloge montre une heure utile au lieu d’un texte contenant la classe et le code de hachage.
Trace des états
Une trace des états enregistre les valeurs des champs après chaque instruction pour montrer comment une suite d’opérations modifie des objets précis.
Une trace des états avec des colonnes pour deux animaux montre qu’un anniversaire pour le premier laisse le second inchangé.

V

Valeur de retour
Une valeur de retour est le résultat qu’une méthode renvoie à son appelant, qui peut le stocker, l’afficher ou l’utiliser dans une expression.
La valeur de retour de r.area() peut être doublée dans une expression ; afficher l’aire seule ne fournit aucune valeur.
Valeur par défaut
Une valeur par défaut est la valeur initiale que Java affecte à un champ sans initialiseur explicite, comme 0, false ou null.
Un champ booléen a la valeur par défaut false ; une variable booléenne locale doit recevoir une valeur avant de pouvoir être lue.
Validation
La validation vérifie qu’une entrée ou une modification proposée respecte les règles de la classe avant de l’accepter dans l’état de l’objet.
Une validation partagée par un constructeur et un mutateur empêche l’un comme l’autre de stocker un état invalide.
Variable d’instance
Une variable d’instance, aussi appelée champ d’instance, stocke une partie de l’état d’un objet et existe aussi longtemps que cet objet.
La variable d’instance age de chaque animal conserve sa propre valeur, même si la déclaration n’apparaît qu’une fois dans Pet.
Variable locale
Une variable locale est déclarée dans un bloc d’une méthode ou d’un constructeur et fournit un stockage temporaire pour cette exécution.
La variable locale total dans une méthode de calcul contient une valeur temporaire que l’objet n’a pas besoin de mémoriser.
void
Le type de retour void indique qu’une méthode ne fournit aucune valeur de retour, même lorsqu’elle modifie l’état ou affiche une sortie.
Une méthode d’anniversaire peut être de type void, car son rôle est d’augmenter l’âge stocké de son objet receveur.

#

@Override
L’annotation @Override demande au compilateur de vérifier qu’une déclaration de méthode remplace une méthode déjà fournie par un supertype.
@Override placé au-dessus de tostring() révèle son erreur de majuscule au lieu de laisser l’affichage automatique inchangé.

À propos de cette unité

Par StudeliSignaler une erreur

Crée ton propre Matériel d'Étude

Transforme tes notes, diapos et documents en Guides d'Étude, Questions Pratiques, Flashcards et 6 autres outils.

Commencer