Restitution TD Machine 2 : Héritage, Polymorphisme et Abstraction en Java¶
Révisions : Constructeurs et Entrées¶
Le Constructeur et this¶
Rôle du Constructeur
Forcer un état initial cohérent au moment de l'allocation mémoire (new). Il porte exactement le nom de la classe et n'a pas de type de retour.
Le mot-clé this lève l'ambiguïté entre les attributs de l'objet courant et les paramètres de la méthode :
public class Robot {
private String nom;
private int batterie;
public Robot(String nom) {
this.nom = nom; // 'this.nom' est l'attribut
this.batterie = 100; // Valeur par défaut forcée
}
}
Les entrées utilisateur avec Scanner¶
Pour rendre le programme interactif, on lit les entrées console avec Scanner.
import java.util.Scanner; // Import obligatoire
public class Main {
public static void main(String[] args) {
Scanner clavier = new Scanner(System.in);
System.out.print("Entrez le nom du robot : ");
String nomSaisi = clavier.nextLine();
Robot r1 = new Robot(nomSaisi);
clavier.close(); // Bonne pratique : libérer la ressource
}
}
L'Héritage : Étendre les capacités¶
Le concept d'Héritage (extends)¶
L'héritage permet de créer une nouvelle classe (Enfant) basée sur une classe existante (Parent) pour spécialiser son comportement.
- Mot-clé :
extends - Relation hiérarchique : Un
DroneEST UNRobot. UnRoverEST UNRobot. - Bénéfice : L'enfant récupère automatiquement toutes les caractéristiques de son parent (pas besoin de réécrire le code commun).
Visibilité : Le compromis protected¶
Le problème du private
Les attributs private du parent sont inaccessibles par l'enfant. L'enfant ne peut pas les lire ni les modifier directement !
La solution : protected
Agit comme private vis-à-vis de l'extérieur, mais autorise l'accès direct aux classes enfants. C'est la visibilité idéale pour l'héritage.
public class Robot {
protected int batterie; // Accessible dans Drone et Rover
protected int x, y;
}
L'initialisation de l'Enfant : super()¶
Un enfant ne peut pas exister sans que sa part "parente" ne soit initialisée.
Règle stricte
Le constructeur de la classe enfant doit obligatoirement appeler le constructeur de la classe parente sur sa toute première ligne avec super().
public class Drone extends Robot {
protected int altitude;
public Drone(String nom) {
super(nom); // Appelle le constructeur de Robot(String nom)
this.altitude = 0; // Initialise l'attribut spécifique au Drone
}
}
Le mot-clé super : Méthodes et Attributs¶
Au-delà des constructeurs, le mot-clé super sert de référence directe à l'instance de la classe parente.
Cas d'usage
- Méthodes : Appeler le comportement d'origine du parent lors d'une redéfinition (pour l'étendre au lieu de l'écraser).
- Attributs : Accéder explicitement à un attribut
protecteddu parent (particulièrement utile si la classe enfant possède un attribut du même nom qui le "masque").
public class Rover extends Robot {
@Override
public void deplacer(int dx, int dy) {
// 1. Appel de la méthode du parent
super.deplacer(dx, dy);
// 2. Accès explicite à l'attribut du parent
if (super.batterie < 10) {
System.out.println("Attention : batterie faible !");
}
}
}
Surcharge vs Redéfinition¶
La Redéfinition (Overriding)¶
Concept : Réécrire dans une classe enfant une méthode héritée du parent afin d'en modifier ou spécialiser le comportement.
public class Rover extends Robot {
protected int distanceParcourue;
@Override // Recommandé : sécurise le code !
public void deplacer(int dx, int dy) {
super.deplacer(dx, dy); // Fait le déplacement standard du Robot
this.distanceParcourue++; // Ajoute l'action spécifique au Rover
}
}
Note : Si on oublie @Override, le code compile quand même. Mais si on fait une faute de frappe, Java créera une nouvelle méthode sans nous alerter !
La Surcharge (Overloading)¶
Concept : Créer plusieurs méthodes (ou constructeurs) avec le même nom mais des paramètres différents au sein de la même classe.
public class Robot {
// Méthode 1 : déplacement avec coût fixe
public void deplacer(int dx, int dy) {
this.deplacer(dx, dy, 1); // Appel de la méthode surchargée (DRY)
}
// Méthode 2 : déplacement avec coût variable
public void deplacer(int dx, int dy, int coutEnergie) {
this.x += dx;
this.y += dy;
this.batterie -= coutEnergie;
}
}
Le piège de la Surcharge¶
Ce qu'il ne faut pas faire
Pour surcharger une méthode, il faut obligatoirement changer la liste des paramètres (nombre, type ou ordre). Changer uniquement le type de retour provoque une erreur de compilation !
// Dans la même classe :
public int calculerEnergie() { return 10; }
// ERREUR DE COMPILATION !
// Le compilateur ne saura pas laquelle appeler.
public double calculerEnergie() { return 10.0; }
Polymorphisme et Object¶
La classe originelle Object¶
En Java, toutes les classes héritent implicitement de la classe mère Object.
Elle fournit un comportement par défaut, notamment la méthode toString().
Par défaut, passer un objet à System.out.println(monRobot) affiche son type et sa référence mémoire (ex: Robot@7a81197d).
Bonne pratique
Toujours redéfinir toString() pour afficher un état lisible.
La magie du Polymorphisme¶
Concept clé : Une référence de type Parent peut pointer vers un objet de type Enfant. Cela permet de manipuler de façon générique des objets très différents !
Robot[] flotte = new Robot[3];
flotte[0] = new Robot("R2D2");
flotte[1] = new Drone("Mavic"); // Un Drone EST un Robot
flotte[2] = new Rover("Curiosity"); // Un Rover EST un Robot
for(int i = 0; i < flotte.length; i++) {
// La machine virtuelle exécutera le toString() spécifique
// au véritable type de l'objet (Drone, Rover ou Robot) !
System.out.println(flotte[i]);
}
Outils Terminal : Classpath et Flux¶
Intégrer des bibliothèques : Le Classpath¶
Les archives .jar contiennent des classes pré-compilées par d'autres développeurs (ex: notre interface graphique FenetreRobot).
L'option -cp (ou -classpath) indique au compilateur et à la JVM où trouver ces fichiers externes :
Commandes dans le terminal
Compilation : javac -cp ".;FenetreRobot.jar" *.java
Exécution : java -cp ".;FenetreRobot.jar" Main
(Le séparateur est un point-virgule sous Windows, et deux-points sous Mac/Linux).
Gestion des erreurs : System.err¶
Jusqu'ici, nous utilisions System.out.println() pour le flux de sortie standard.
La classe System propose un flux séparé pour les alertes et erreurs : System.err.
Avantages :
- Souvent mis en évidence en rouge dans la console ou l'IDE.
- Permet de rediriger (dans le terminal) les logs normaux vers un fichier, et les erreurs vers un autre.
if (batterie <= 0) {
System.err.println("ERREUR : Plus de batterie !");
} else {
this.x += dx; // Le robot bouge
}
L'Abstraction et les Interfaces¶
La contrainte architecturale de Java¶
Règle d'or : Pas d'héritage multiple de classes !
En Java, une classe ne peut utiliser extends que sur UNE SEULE autre classe. Cela évite les ambiguïtés si deux parents définissent la même méthode.
Mais comment faire si une StationMeteo est à la fois une Machine ET un objet Connectable au réseau ?
→ On utilise les Interfaces.
Classes Abstraites vs Interfaces¶
Classe Abstraite (abstract class)
- Classe "incomplète" servant de base pour l'héritage (
extends). - Peut contenir des attributs d'état et du code concret.
- Impossible de l'instancier directement (
new Machine()interdit).
Interface (interface)
- Un contrat pur sans aucun attribut d'état.
- Permet de contourner l'interdiction de l'héritage multiple : une classe peut implémenter (
implements) une multitude d'interfaces !
Application : Le code contractuel¶
// L'interface définit le contrat (méthodes obligatoires)
public interface Connectable {
void seConnecterReseau();
}
// La classe respecte le contrat et fournit le code
public class StationMeteo extends Machine implements Connectable {
public StationMeteo(String num) {
super(num);
}
// Le compilateur exige la présence de cette méthode !
@Override
public void seConnecterReseau() {
System.out.println("Connexion au serveur établie.");
}
}
Bilan¶
Bilan du TD¶
- Héritage : Mot-clé
extends. Permet de factoriser. Utiliserprotectedpour l'encapsulation etsuper()pour initialiser. - Surcharge vs Redéfinition :
- Surcharge (Overload) : Même classe, même nom, paramètres différents.
- Redéfinition (Override) : Classe enfant, comportement spécialisé.
- Polymorphisme : Manipuler un ensemble de
DroneetRovervia un simple tableau deRobot. La méthodetoString()est appelée dynamiquement. - Abstraction : Si on veut partager un comportement entre des classes non liées hiérarchiquement, on utilise des
interfaces.
Page rédigée à l'aide de Gemini (pas par Gemini)