0% ont trouvé ce document utile (0 vote)
0 vues27 pages

Cours_Java_POO_Complet

Ce document est un cours complet sur la Programmation Orientée Objet en Java, destiné aux étudiants de première année en Génie Logiciel. Il couvre des concepts fondamentaux tels que les identifiants, les règles de déclaration, les modificateurs d'accès, l'héritage, le polymorphisme, ainsi que les classes abstraites et les interfaces. Chaque chapitre présente des exemples pratiques pour illustrer les principes de la programmation en Java.

Transféré par

Mohamed aziz
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats DOCX, PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
0 vues27 pages

Cours_Java_POO_Complet

Ce document est un cours complet sur la Programmation Orientée Objet en Java, destiné aux étudiants de première année en Génie Logiciel. Il couvre des concepts fondamentaux tels que les identifiants, les règles de déclaration, les modificateurs d'accès, l'héritage, le polymorphisme, ainsi que les classes abstraites et les interfaces. Chaque chapitre présente des exemples pratiques pour illustrer les principes de la programmation en Java.

Transféré par

Mohamed aziz
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats DOCX, PDF, TXT ou lisez en ligne sur Scribd

COURS COMPLET

Programmation Orientée Objet en Java


1ère Année — Génie Logiciel
Basé sur les cours de Mohamed Ramzi HADDAD — ENIT
Chapitre 1 — Bases du Langage Java

1.1 Identifieurs et conventions de nommage


Un identifieur est le nom donné à une classe, une méthode, un attribut ou une variable. En Java :
• Commence par une lettre, un underscore (_) ou un symbole monétaire ($)
• Après le premier caractère, peut contenir des chiffres
• Longueur illimitée (mais restez raisonnables !)
• Sensible à la casse : MaClasse ≠ maclasse

Convention camelCase (obligatoire en pratique) :


• Nom de classe → commence par une MAJUSCULE : Personne, CompteBancaire
• Méthode / variable → commence par une minuscule : calculerSalaire, montantTotal
• Constante (final static) → tout en MAJUSCULES : TAUX_TVA, MAX_ESSAIS

// ✅ Bons identifieurs
class CompteBancaire { }
double tauxInteret = 0.05;
final int MAX_TENTATIVES = 3;

// ❌ Mauvais identifieurs
class comptebancaire { } // majuscule manquante
double TauxInteret = 0.05; // réservé aux classes
int 2valeur = 5; // commence par un chiffre → ERREUR

1.2 Règles de déclaration des fichiers source


• Un seul fichier = une seule classe public
• Le nom du fichier doit correspondre exactement au nom de la classe public
• Plusieurs classes non-public peuvent cohabiter dans le même fichier
• L'instruction package (si présente) doit être la première ligne non commentée
• Les import viennent après le package, avant la classe

package [Link]; // 1. package en premier

import [Link]; // 2. imports ensuite


import [Link];

public class Personne { // 3. classe publique (nom = nom du fichier)


// ...
}

class PersonneHelper { // 4. classe non-public → autorisée dans le même


fichier
// ...
}

1.3 Modificateurs d'accès


Il existe 4 niveaux d'accès (3 mots-clés + l'accès par défaut) :
Modificateur Même classe Même package Sous-classe Partout
public ✅ ✅ ✅ ✅
protected ✅ ✅ ✅ ❌
(défaut) ✅ ✅ ❌ ❌
private ✅ ❌ ❌ ❌

💡 Règle d'or de l'encapsulation


Déclarez toujours vos attributs private.
Exposez uniquement ce qui doit l'être via des méthodes public (getters/setters).
Utilisez protected uniquement pour les membres devant être accessibles aux sous-classes.

1.4 Le modificateur final


• Classe final → ne peut pas être héritée
• Méthode final → ne peut pas être redéfinie dans les sous-classes
• Variable/attribut final → sa valeur ne peut plus changer après initialisation (constante)
• Référence final → elle doit toujours pointer vers le même objet (mais l'objet peut changer
d'état !)

final class StringImmuable { } // impossible d'hériter

class Animal {
final void respirer() { /* ... */ } // non redéfinissable
}

class Compte {
private final String iban; // doit être initialisé dans le
constructeur
private static final double TAUX = 0.05; // constante de classe

public Compte(String iban) {


[Link] = iban; // OK : première et unique affectation
}
}

1.5 Variables et méthodes statiques


Les membres static appartiennent à la CLASSE, pas aux instances. Il n'en existe qu'une seule
copie, partagée par tous les objets.

public class Compteur {


private static int nbInstances = 0; // partagé entre tous les objets
private int id;

public Compteur() {
nbInstances++;
[Link] = nbInstances;
}

public static int getNbInstances() { // méthode statique


return nbInstances; // ✅ accès OK
// return [Link]; // ❌ ERREUR : pas de 'this' dans static
}
}

// Utilisation
Compteur c1 = new Compteur();
Compteur c2 = new Compteur();
[Link]([Link]()); // 2

⚠️Attention
Une méthode static ne peut PAS accéder directement aux membres non-static (attributs
d'instance, méthodes d'instance).
Elle n'a pas accès au mot-clé 'this'.
Chapitre 2 — Classes, Objets et Constructeurs

2.1 Structure d'une classe Java


Une classe est un modèle (blueprint) qui décrit les attributs et comportements de ses futurs objets.

public class Voiture {

// ── Attributs (état de l'objet) ────────────────────


private String marque;
private String modele;
private int annee;
private double kilometrage;
private static int nbVoitures = 0; // attribut de classe

// ── Constructeur ────────────────────────────────────
public Voiture(String marque, String modele, int annee) {
[Link] = marque;
[Link] = modele;
[Link] = annee;
[Link] = 0;
nbVoitures++;
}

// ── Accesseurs (getters) ────────────────────────────


public String getMarque() { return marque; }
public String getModele() { return modele; }
public int getAnnee() { return annee; }
public double getKilometrage() { return kilometrage; }

// ── Mutateurs (setters) ─────────────────────────────


public void setKilometrage(double km) {
if (km >= 0) [Link] = km;
}

// ── Méthodes métier ─────────────────────────────────


public void rouler(double distance) {
if (distance > 0) kilometrage += distance;
}

// ── toString ────────────────────────────────────────
@Override
public String toString() {
return marque + " " + modele + " (" + annee + ") — " + kilometrage + "
km";
}

public static int getNbVoitures() { return nbVoitures; }


}

2.2 Constructeurs en détail


Le constructeur initialise un objet. Il porte le même nom que la classe et n'a PAS de type de retour.

Règles essentielles :
• Si aucun constructeur n'est défini, Java fournit un constructeur par défaut (sans paramètre,
corps vide)
• Dès qu'on définit un constructeur paramétré, le constructeur par défaut n'est plus fourni
automatiquement
• this() appelle un autre constructeur de la même classe (doit être en première ligne)
• super() appelle le constructeur de la classe mère (doit être en première ligne)
• this() et super() sont mutuellement exclusifs dans un même constructeur

public class Rectangle {


private double largeur;
private double hauteur;

// Constructeur complet
public Rectangle(double largeur, double hauteur) {
[Link] = largeur;
[Link] = hauteur;
}

// Constructeur surchargé → carré


public Rectangle(double cote) {
this(cote, cote); // appelle le constructeur ci-dessus
}

// Constructeur par défaut manuel


public Rectangle() {
this(1.0, 1.0); // appelle Rectangle(double, double)
}

public double surface() { return largeur * hauteur; }


public double perimetre() { return 2 * (largeur + hauteur); }
}

// Utilisation
Rectangle r1 = new Rectangle(5, 3); // 5 × 3
Rectangle r2 = new Rectangle(4); // 4 × 4 (carré)
Rectangle r3 = new Rectangle(); // 1 × 1

2.3 Le mot-clé this


• this fait référence à l'objet courant (celui sur lequel la méthode est appelée)
• [Link] : distingue l'attribut d'un paramètre portant le même nom
• [Link]() : appelle une méthode de l'objet courant
• return this : utile pour le chainage de méthodes (pattern Builder)

public class Builder {


private String nom;
private int age;

public Builder setNom(String nom) { [Link] = nom; return this; }


public Builder setAge(int age) { [Link] = age; return this; }
public String build() { return nom + " (" + age + " ans)"; }
}

// Chainage fluide grâce à return this


String resultat = new Builder().setNom("Alice").setAge(22).build();
Chapitre 3 — Héritage

3.1 Principe de l'héritage


L'héritage permet à une classe fille (sous-classe) de réutiliser et spécialiser les membres d'une
classe mère (super-classe). En Java, l'héritage est simple (une seule classe mère).

Relation est-un (is-a)


Un Chien EST UN Animal → héritage justifié
Un Moteur EST UNE Voiture → ❌ Non ! C'est une relation a-un (has-a) → utiliser la composition

// ── Classe mère ─────────────────────────────────────────


public class Animal {
private String nom;
private int age;

public Animal(String nom, int age) {


[Link] = nom;
[Link] = age;
}

public void manger() { [Link](nom + " mange."); }


public void dormir() { [Link](nom + " dort."); }

public String getNom() { return nom; }


public int getAge() { return age; }

@Override
public String toString() { return nom + " (" + age + " ans)"; }
}

// ── Classe fille ─────────────────────────────────────────


public class Chien extends Animal {
private String race;

public Chien(String nom, int age, String race) {


super(nom, age); // appel obligatoire du constructeur parent
[Link] = race;
}

public void aboyer() { [Link](getNom() + " : Wouf !"); }

@Override
public String toString() {
return [Link]() + " — Race : " + race;
}
}

// ── Utilisation ──────────────────────────────────────────
Chien rex = new Chien("Rex", 3, "Berger Allemand");
[Link](); // hérité de Animal
[Link](); // propre à Chien
[Link](rex); // toString redéfinie

3.2 Surcharge vs Redéfinition


Critère Surcharge (Overload) Redéfinition (Override)
Lieu Même classe (ou sous-classe) Classe fille uniquement
Paramètres Liste DIFFÉRENTE Liste IDENTIQUE
Type de retour Peut différer Même type ou sous-type (covariant)
Accès Peut changer Pas plus restrictif
Lien héritage Non requis Requis
@Override Non applicable Recommandé (vérifié à la compile)

public class Calculatrice {


// SURCHARGE : même nom, paramètres différents
public int additionner(int a, int b) { return a + b; }
public double additionner(double a, double b) { return a + b; }
public int additionner(int a, int b, int c) { return a + b + c; }
}

public class Animal {


public String parler() { return "..."; }
}
public class Chat extends Animal {
@Override
public String parler() { return "Miaou !"; } // REDÉFINITION
}

3.3 Transtypage (Casting)


Java permet de convertir une référence d'un type vers un autre, à condition qu'il existe une relation
d'héritage.

Upcasting (vers le type parent) — implicite, toujours sûr :


Animal a = new Chien("Rex", 3, "Labrador"); // upcasting implicite
// a ne voit que les méthodes de Animal !
[Link](); // ✅ OK
// [Link](); // ❌ Erreur de compilation : Animal ne connaît pas aboyer()

Downcasting (vers le type fils) — explicite, risqué → utiliser instanceof :


Animal a = new Chien("Rex", 3, "Labrador");

// Test de sécurité avant le downcasting


if (a instanceof Chien) {
Chien c = (Chien) a; // downcasting explicite
[Link](); // ✅ maintenant accessible
}

// Java 16+ : pattern matching (plus élégant)


if (a instanceof Chien c) {
[Link](); // c est déjà casté
}
Chapitre 4 — Polymorphisme

4.1 Qu'est-ce que le polymorphisme ?


Le polymorphisme ("plusieurs formes") permet à une référence de type parent d'appeler la version
redéfinie d'une méthode selon le TYPE RÉEL de l'objet référencé, et ceci au moment de l'exécution
(late binding).

La résolution se fait en deux temps :


• À la COMPILATION : le compilateur vérifie que la méthode existe dans le type de la
référence
• À l'EXÉCUTION : la JVM appelle la version de la méthode correspondant au type RÉEL de
l'objet

public abstract class Forme {


public abstract double surface();
public void afficher() {
[Link]("Surface = " + surface());
}
}

public class Cercle extends Forme {


private double rayon;
public Cercle(double rayon) { [Link] = rayon; }
@Override
public double surface() { return [Link] * rayon * rayon; }
}

public class Rectangle extends Forme {


private double l, h;
public Rectangle(double l, double h) { this.l=l; this.h=h; }
@Override
public double surface() { return l * h; }
}

// ── Polymorphisme en action ───────────────────────────


List<Forme> formes = new ArrayList<>();
[Link](new Cercle(5)); // Forme → Cercle
[Link](new Rectangle(4, 6)); // Forme → Rectangle
[Link](new Cercle(3)); // Forme → Cercle

for (Forme f : formes) {


[Link](); // appelle LA BONNE surface() selon le type réel
// Cercle → surface = 78.54
// Rectangle → surface = 24.0
}

💡 Avantage majeur du polymorphisme


On peut écrire du code générique (boucle sur List<Forme>) qui fonctionne
automatiquement avec tous les sous-types présents et futurs.
C'est le principe Ouvert/Fermé : ouvert à l'extension, fermé à la modification.
Chapitre 5 — Classes Abstraites et Interfaces

5.1 Classes abstraites


Une classe abstraite est une classe partielle : elle définit un contrat partiel et ne peut pas être
instanciée directement.

Règles :
• Mot-clé abstract sur la classe
• Peut avoir des méthodes concrètes ET des méthodes abstraites
• Une classe qui a au moins une méthode abstraite DOIT être déclarée abstract
• Une classe concrète héritière DOIT implémenter toutes les méthodes abstraites
• Peut avoir un constructeur (appelé via super() depuis la fille)
• Ne peut pas être final (contradiction logique)

public abstract class Vehicule {


private String immatriculation;
private int poidsAVide;

public Vehicule(String immatriculation, int poidsAVide) {


[Link] = immatriculation;
[Link] = poidsAVide;
}

// Méthode abstraite → chaque véhicule calcule sa vitesse différemment


public abstract int calculerVitesseMaximale();

// Méthode concrète → comportement commun à tous


public void afficher() {
[Link](immatriculation + " → vitesse max : "
+ calculerVitesseMaximale() + " km/h");
}

public String getImmatriculation() { return immatriculation; }


public int getPoidsAVide() { return poidsAVide; }
}

public class PetitBus extends Vehicule {


private int nbPlaces;

public PetitBus(String immat, int nbPlaces) {


super(immat, 4); // poids à vide = 4 tonnes
[Link] = nbPlaces;
}

@Override
public int calculerVitesseMaximale() { return 150; }
}

public class CamionCiterne extends Vehicule {


private int charge; // charge actuelle en tonnes

public CamionCiterne(String immat) {


super(immat, 3); // poids à vide = 3 tonnes
[Link] = 0;
}

public void charger(int poids) {


if (charge + poids <= 10) charge += poids; // max 10 tonnes
}
@Override
public int calculerVitesseMaximale() {
return charge < 4 ? 120 : 90;
}
}

5.2 Interfaces
Une interface est un CONTRAT PUR : elle définit des méthodes que toute classe implémentante
doit fournir. C'est le mécanisme d'héritage multiple de Java.

Propriétés clés :
• Mot-clé interface
• Toutes les méthodes sont implicitement public et abstract (Java 7 et avant)
• Tous les attributs sont implicitement public static final (constantes)
• Pas de constructeur, pas d'instanciation directe
• Une classe peut implémenter PLUSIEURS interfaces
• Une interface peut hériter de plusieurs autres interfaces (extends multiple)
• Java 8+ : méthodes default et static dans les interfaces

// ── Interface ────────────────────────────────────────────
public interface Louable {
double TARIF_HORAIRE = 200.0; // implicitement public static final

double facturer(int distanceKm); // implicitement public abstract


}

public interface Comparable<T> {


int compareTo(T autre);
}

// ── Classe implémentant une interface ────────────────────


public class PetitBus extends Vehicule implements Louable {
private int nbPlaces;

public PetitBus(String immat, int nbPlaces) {


super(immat, 4);
[Link] = nbPlaces;
}

@Override public int calculerVitesseMaximale() { return 150; }

@Override
public double facturer(int distanceKm) {
double dureeH = (double) distanceKm / calculerVitesseMaximale();
return dureeH * TARIF_HORAIRE;
}
}

// ── Utilisation polymorphe via interface ─────────────────


Louable l = new PetitBus("TN-123-AB", 20);
[Link]([Link](300) + " DT"); // 400.0 DT

5.3 Classe abstraite vs Interface — Quand utiliser quoi ?


Critère Classe Abstraite Interface
Instanciation ❌ Non ❌ Non
Constructeur ✅ Oui ❌ Non
Attributs Tous types Constantes uniquement
Méthodes concrètes ✅ Oui ✅ (default Java 8+)
Héritage/ Héritage simple Implémentation multiple
implémentation
Relation exprimée est-un partiel peut-faire (capacité)
Usage typique Factoriser du code commun Définir un contrat/rôle
Chapitre 6 — Les Collections Java

6.1 Vue d'ensemble


Les collections Java (package [Link]) permettent de stocker et manipuler des groupes d'objets de
façon bien plus puissante que les tableaux.

Les 4 grandes familles :


• List — collection ordonnée avec doublons autorisés. Accès par index.
• Set — collection d'éléments uniques (sans doublons).
• Map — collection de paires clé→valeur. Clés uniques.
• Queue — file d'attente (FIFO ou priorité).

6.2 List — ArrayList et LinkedList


import [Link].*;

// ArrayList : accès rapide par index, insertion/suppression lente au milieu


List<String> villes = new ArrayList<>();
[Link]("Tunis");
[Link]("Sfax");
[Link]("Sousse");
[Link](0, "Bizerte"); // insertion à l'index 0

[Link]([Link](1)); // Tunis
[Link]([Link]()); // 4
[Link]([Link]("Sfax")); // true
[Link]("Sousse");

// Parcours avec for-each


for (String v : villes) {
[Link](v);
}

// Parcours avec Iterator


Iterator<String> it = [Link]();
while ([Link]()) {
String v = [Link]();
if ([Link]("Sfax")) [Link](); // suppression sécurisée en cours de
parcours
}

6.3 Set — HashSet et TreeSet


// HashSet : pas d'ordre garanti, O(1) pour add/contains/remove
Set<String> prenoms = new HashSet<>();
[Link]("Alice");
[Link]("Bob");
[Link]("Alice"); // doublon ignoré silencieusement
[Link]([Link]()); // 2 (pas 3 !)

// TreeSet : éléments triés, O(log n)


Set<Integer> notes = new TreeSet<>();
[Link](15); [Link](8); [Link](19); [Link](12);
[Link](notes); // [8, 12, 15, 19] — trié automatiquement
6.4 Map — HashMap et TreeMap
// HashMap : table de hachage, pas d'ordre garanti
Map<String, Integer> notes = new HashMap<>();
[Link]("Alice", 18);
[Link]("Bob", 14);
[Link]("Charlie", 16);

[Link]([Link]("Alice")); // 18
[Link]([Link]("Bob")); // true
[Link]("Charlie");

// Parcours des paires clé/valeur


for ([Link]<String, Integer> e : [Link]()) {
[Link]([Link]() + " → " + [Link]());
}

// Exemple exam Taxis : flotte identifiée par immatriculation


Map<String, Taxi> flotte = new HashMap<>();
[Link]("TN-001", new Taxi("TN-001", ...));
Taxi t = [Link]("TN-001"); // accès O(1)

6.5 Tri des collections — Comparable et Comparator


Pour trier des objets complexes, Java propose deux mécanismes :

1. Interface Comparable<T> — ordre naturel (un seul critère) :


public class Joueur implements Comparable<Joueur> {
private String nom;
private double qualiteDeJeu;
private boolean blesse;

// Ordre : non-blessé > blessé, puis qualité décroissante


@Override
public int compareTo(Joueur autre) {
// D'abord : les non-blessés sont "supérieurs"
if ([Link] != [Link]) {
return [Link] ? -1 : 1; // blessé → inférieur
}
// Ensuite : qualité décroissante
return [Link]([Link], [Link]);
}
}

List<Joueur> joueurs = new ArrayList<>();


// ... remplir ...
[Link](joueurs); // utilise compareTo

2. Interface Comparator<T> — critères multiples/externes :


// Comparateur de Taxi par distance à un point de départ
public class ComparateurTaxiDistance implements Comparator<Taxi> {
private Localisation depart;

public ComparateurTaxiDistance(Localisation depart) {


[Link] = depart;
}

@Override
public int compare(Taxi t1, Taxi t2) {
double d1 = [Link]([Link](), depart);
double d2 = [Link]([Link](), depart);
return [Link](d1, d2);
}
}

// Tri des taxis par distance au point de départ


[Link](taxis, new ComparateurTaxiDistance([Link]()));

// Java 8+ version lambda (plus concise)


[Link]((t1, t2) -> [Link](
[Link]([Link](), depart),
[Link]([Link](), depart)
));

6.6 Redéfinir equals() et hashCode()


Pour que contains(), remove(), indexOf() fonctionnent correctement sur des objets personnalisés,
vous devez redéfinir equals() (et hashCode() pour les collections basées sur le hachage).

public class Personne {


private String cin;
private String nom;

@Override
public boolean equals(Object obj) {
if (this == obj) return true; // même référence
if (!(obj instanceof Personne)) return false;
Personne autre = (Personne) obj;
return [Link]([Link]); // égalité sur CIN
}

@Override
public int hashCode() {
return [Link](); // cohérent avec equals !
}
}

⚠️Règle equals/hashCode
Si [Link](b) → [Link]() doit obligatoirement == [Link]().
Toujours redéfinir les deux ensemble. Sans hashCode correct,
les HashMap et HashSet ne fonctionneront pas correctement.
Chapitre 7 — Exercices Résolus (Examens ENIT)

7.1 Exercice 1 — Gestion des équipes de football (2016/2017)

Énoncé résumé
Modéliser : Personne (CIN), Joueur, Entraineur, Médecin, Kinésithérapeute.
Les Joueurs implémentent Comparable (qualité de jeu + état).
Entraineur et Médecin sont des Sélectionneurs (interface).
La classe Equipe contient une collection de Personnes.

Diagramme de classes (UML simplifié) :


<<interface>>
Selectionneur
|
+-----------+-----------+
| |
Entraineur Medecin
\ /
\ /
+---> Sportif <----+
| ^
| |
Joueur (extends)
| |
+--------+
Personne (abstract)
|
PersonnelMedical (abstract)
/ \
Medecin Kinesitherapeute

Solution complète :
// ═══ Personne (classe de base abstraite) ════════════════
public abstract class Personne {
private String cin;
private String nom;

public Personne(String cin, String nom) {


[Link] = cin;
[Link] = nom;
}

public abstract String getRole();

@Override
public String toString() {
return "CIN:" + cin + " | Nom:" + nom + " | Rôle:" + getRole();
}

public String getCin() { return cin; }


public String getNom() { return nom; }

@Override
public boolean equals(Object obj) {
if (!(obj instanceof Personne)) return false;
return [Link](((Personne) obj).cin);
}
}

// ═══ Interface Sélectionneur ═════════════════════════════


public interface Selectionneur {
List<Joueur> selectionner(List<Joueur> joueurs);
}

// ═══ Sportif (classe intermédiaire abstraite) ════════════


public abstract class Sportif extends Personne {
private boolean aJoueNational;

public Sportif(String cin, String nom, boolean aJoueNational) {


super(cin, nom);
[Link] = aJoueNational;
}

public boolean isaJoueNational() { return aJoueNational; }


}

// ═══ Joueur ══════════════════════════════════════════════


public class Joueur extends Sportif implements Comparable<Joueur> {
private double qualiteDeJeu;
private boolean blesse;

public Joueur(String cin, String nom, boolean aJoueNational) {


super(cin, nom, aJoueNational);
[Link] = 50.0; // valeur initiale
[Link] = false;
}

@Override public String getRole() { return "Joueur"; }

// +5% après un match


public void jouerUnMatch() {
qualiteDeJeu *= 1.05;
}

// +2% à l'entraînement (si non blessé)


public void sentrainer() {
if (!blesse) qualiteDeJeu *= 1.02;
}

// Ordre : non-blessé > blessé, puis qualité décroissante


@Override
public int compareTo(Joueur autre) {
if ([Link] != [Link])
return [Link] ? -1 : 1;
return [Link]([Link], [Link]);
}

public double getQualiteDeJeu() { return qualiteDeJeu; }


public boolean isBlesse() { return blesse; }
public void setBlesse(boolean b){ [Link] = b; }
}

// ═══ Entraineur (Sportif + Selectionneur) ════════════════


public class Entraineur extends Sportif implements Selectionneur {

public Entraineur(String cin, String nom, boolean aJoueNational) {


super(cin, nom, aJoueNational);
}

@Override public String getRole() { return "Entraineur"; }


public void entrainer(List<Joueur> joueurs) {
for (Joueur j : joueurs) [Link]();
}

// Sélectionne les 11 meilleurs


@Override
public List<Joueur> selectionner(List<Joueur> joueurs) {
List<Joueur> copie = new ArrayList<>(joueurs);
[Link](copie); // utilise compareTo de Joueur
return [Link](0, [Link](11, [Link]()));
}
}

// ═══ PersonnelMedical (abstraite) ════════════════════════


public abstract class PersonnelMedical extends Personne {
private String diplome;

public PersonnelMedical(String cin, String nom, String diplome) {


super(cin, nom);
[Link] = diplome;
}

// +1% si non blessé


public void masser(Joueur j) {
if (![Link]()) {
// accès via méthode interne pour sous-classes
appliquerMassage(j);
}
}

protected void appliquerMassage(Joueur j) {


// incrémenté via setter interne (qualité * 1.01)
[Link](); // simplifié — en pratique : setter setQualite
}
}

// ═══ Médecin (PersonnelMedical + Selectionneur) ══════════


public class Medecin extends PersonnelMedical implements Selectionneur {

public Medecin(String cin, String nom, String diplome) {


super(cin, nom, diplome);
}

@Override public String getRole() { return "Médecin"; }

public void soigner(Joueur j) { [Link](false); }

// Sélectionne tous les joueurs non blessés


@Override
public List<Joueur> selectionner(List<Joueur> joueurs) {
List<Joueur> aptes = new ArrayList<>();
for (Joueur j : joueurs)
if (![Link]()) [Link](j);
return aptes;
}
}

// ═══ Kinésithérapeute ════════════════════════════════════


public class Kinesitherapeute extends PersonnelMedical {

public Kinesitherapeute(String cin, String nom, String diplome) {


super(cin, nom, diplome);
}

@Override public String getRole() { return "Kinésithérapeute"; }


// hérite masser() de PersonnelMedical
}
// ═══ Equipe ══════════════════════════════════════════════
public class Equipe {
private String nom;
private Map<String, Personne> membres; // CIN → Personne

public Equipe(String nom) {


[Link] = nom;
[Link] = new HashMap<>();
}

// Ajoute uniquement si le CIN n'existe pas déjà


public void ajouterPersonne(Personne p) {
if (![Link]([Link]()))
[Link]([Link](), p);
}

// Supprime par CIN


public void supprimerPersonne(String cin) {
[Link](cin);
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder("Équipe : " + nom + "\n");
for (Personne p : [Link]())
[Link](" ").append(p).append("\n");
return [Link]();
}

// Q3 : une réunion de sélectionneurs → List<Selectionneur>


// (Selectionneur est une interface commune à Entraineur et Medecin)
private List<Selectionneur> selectionneurs = new ArrayList<>();
}

7.2 Exercice 2 — Centrale de réservation de Taxis (2023/2024)

Énoncé résumé
Modéliser : Localisation, Demande, Taxi, interface RouteurTaxi,
interface ReceveurDemande, et CentraleReservation.
Algorithme de routage : sélectionner le taxi libre le plus proche du départ.

// ═══ Localisation (fournie) ══════════════════════════════


public class Localisation {
private int x, y;
public Localisation(int x, int y) { this.x=x; this.y=y; }
public int getX() { return x; }
public int getY() { return y; }
public static double distance(Localisation l1, Localisation l2) {
int dx = l1.x - l2.x, dy = l1.y - l2.y;
return [Link](dx*dx + dy*dy);
}
}

// ═══ Demande ═════════════════════════════════════════════


public class Demande {
private String cinClient;
private Localisation depart;
private Localisation arrivee;

public Demande(String cinClient, Localisation depart, Localisation arrivee) {


[Link] = cinClient;
[Link] = depart;
[Link] = arrivee;
}

public String getCinClient() { return cinClient; }


public Localisation getDepart() { return depart; }
public Localisation getArrivee() { return arrivee; }
}

// ═══ Taxi ════════════════════════════════════════════════


public class Taxi {
private final String immatriculation; // immuable
private Localisation position;
private Demande demandeCourante; // null si libre

public Taxi(String immatriculation, Localisation position) {


[Link] = immatriculation;
[Link] = position;
[Link] = null;
}

public boolean estLibre() { return demandeCourante == null; }

public String getImmatriculation() { return immatriculation; }


public Localisation getPosition() { return position; }
public Demande getDemandeCourante() { return demandeCourante; }

public void setPosition(Localisation pos) { [Link] = pos; }


public void setDemandeCourante(Demande d) { [Link] =
d; }
}

// ═══ Interface RouteurTaxi ════════════════════════════════


public interface RouteurTaxi {
Taxi traiterDemande(Demande demande, List<Taxi> taxis);
}

// ═══ Interface ReceveurDemande ════════════════════════════


public interface ReceveurDemande {
List<Demande> getNouvellesDemandes();
}

// ═══ RouteurProximite (algorithme de tri) ════════════════


public class RouteurProximite implements RouteurTaxi {

@Override
public Taxi traiterDemande(Demande demande, List<Taxi> taxis) {
Localisation depart = [Link]();

// Trier les taxis par distance au point de départ


List<Taxi> tries = new ArrayList<>(taxis);
[Link]((t1, t2) -> [Link](
[Link]([Link](), depart),
[Link]([Link](), depart)
));

// Retourner le premier taxi libre


for (Taxi t : tries) {
if ([Link]()) return t;
}
return null; // aucun taxi libre
}
}

// ═══ CentraleReservation ═════════════════════════════════


public class CentraleReservation {
private List<Taxi> flotte = new ArrayList<>();
private List<Demande> demandesEnAttente = new ArrayList<>();
private List<ReceveurDemande> receveurs = new ArrayList<>();
private RouteurTaxi routeur;

public CentraleReservation(RouteurTaxi routeur) {


[Link] = routeur;
}

public void ajouterTaxi(Taxi t) {


if (![Link](t)) [Link](t);
}

public void supprimerTaxi(Taxi t) { [Link](t); }

public void traiterDemandes() {


// 1. Collecter toutes les nouvelles demandes
for (ReceveurDemande r : receveurs)
[Link]([Link]());

// 2. Traiter chaque demande en attente


Iterator<Demande> it = [Link]();
while ([Link]()) {
Demande d = [Link]();
Taxi taxi = [Link](d, flotte);
if (taxi != null && [Link]()) { // double vérification
[Link](d);
[Link](); // suppression sécurisée
}
}
}

public void traiterLesCoursesAchevees() {


for (Taxi t : flotte) {
if (![Link]()) {
Localisation dest = [Link]().getArrivee();
if ([Link]([Link](), dest) == 0) {
[Link](null); // libérer le taxi
}
}
}
}
}

7.3 Exercice 3 — Parc de véhicules avec camions (2024/2025)


Énoncé résumé
Véhicules : PetitBus, CamionCiterne, CamionBâché.
Interface Louable pour PetitBus : facturer(int distance) = 200 DT/h.
ParcVehicules : ajouterVehicule(), getVehiculeLePlusLent().
ConvoiDeLocation : calculerCoutLocation(int distance).

// ═══ Interface Chargeable ════════════════════════════════


public interface Chargeable {
void charger(int poids);
int getChargeMaximale();
int getChargeActuelle();
}

// ═══ Vehicule (abstraite) ════════════════════════════════


public abstract class Vehicule {
private final String immatriculation;
private final int poidsAVide;

public Vehicule(String immat, int poidsAVide) {


[Link] = immat;
[Link] = poidsAVide;
}

public abstract int calculerVitesseMaximale();

public String getImmatriculation() { return immatriculation; }


public int getPoidsAVide() { return poidsAVide; }
}

// ═══ Interface Louable ═══════════════════════════════════


public interface Louable {
double TARIF_HORAIRE = 200.0;
double facturer(int distanceKm);
}

// ═══ PetitBus ════════════════════════════════════════════


public class PetitBus extends Vehicule implements Louable {
private int nbPlaces;

public PetitBus(String immat, int nbPlaces) {


super(immat, 4);
[Link] = nbPlaces;
}

@Override public int calculerVitesseMaximale() { return 150; }

@Override
public double facturer(int distanceKm) {
double heures = (double) distanceKm / calculerVitesseMaximale();
return heures * TARIF_HORAIRE;
}
}

// ═══ CamionCiterne ═══════════════════════════════════════


public class CamionCiterne extends Vehicule implements Chargeable {
private static final int CHARGE_MAX = 10;
private int charge;

public CamionCiterne(String immat) { super(immat, 3); [Link] = 0; }

@Override public int getChargeMaximale() { return CHARGE_MAX; }


@Override public int getChargeActuelle() { return charge; }

@Override
public void charger(int poids) {
if (charge + poids <= CHARGE_MAX) charge += poids;
}

@Override
public int calculerVitesseMaximale() { return charge < 4 ? 120 : 90; }
}

// ═══ ParcVehicules ═══════════════════════════════════════


public class ParcVehicules {
private List<Vehicule> vehicules = new ArrayList<>();

public void ajouterVehicule(Vehicule v) { [Link](v); }

public Vehicule getVehiculeLePlusLent() {


if ([Link]()) return null;
Vehicule lePlusLent = [Link](0);
for (Vehicule v : vehicules)
if ([Link]() <
[Link]())
lePlusLent = v;
return lePlusLent;
}
}
// ═══ ConvoiDeLocation ════════════════════════════════════
public class ConvoiDeLocation {
private List<Louable> vehiculesLoues = new ArrayList<>();

public void ajouterVehicule(Louable v) { [Link](v); }

public double calculerCoutLocation(int distanceKm) {


double total = 0;
for (Louable l : vehiculesLoues)
total += [Link](distanceKm);
return total;
}
}
Chapitre 8 — Mémo Examen & Conseils Stratégiques

8.1 Checklist avant de rendre votre copie


• ✅ Tous les attributs sont private
• ✅ Constructeurs paramétrés uniquement (l'énoncé le demande souvent)
• ✅ @Override sur chaque méthode redéfinie
• ✅ super(params) en première ligne de chaque constructeur de classe fille
• ✅ equals() redéfini si on fait des recherches/suppressions par valeur
• ✅ compareTo() retourne négatif si this < autre, 0 si égal, positif si this > autre
• ✅ Interface pour les rôles transversaux (Louable, Selectionneur, RouteurTaxi...)
• ✅ Classe abstraite pour factoriser le code commun (Vehicule, Sportif...)
• ✅ Pas de duplication de code — utiliser [Link]() si besoin

8.2 Pièges classiques à éviter

❌ Piège 1 : oublier super() dans le constructeur fils


Si la classe mère n'a pas de constructeur sans argument,
Java NE génère PAS d'appel super() automatique.
→ Toujours appeler super(params) explicitement en première ligne.

❌ Piège 2 : this() et super() ensemble


this() et super() ne peuvent PAS coexister dans un même constructeur.
Si this() est présent, c'est LUI qui appellera super() indirectement.

❌ Piège 3 : méthode statique accédant aux membres d'instance


public static void methode() { return [Link]; } // ❌ ERREUR
Les méthodes statiques n'ont pas accès à 'this' ni aux membres non-static.

❌ Piège 4 : compareTo incohérent avec equals


Si [Link](b) == 0, cela devrait signifier [Link](b).
Incohérence → comportements imprévisibles dans TreeSet/TreeMap.

8.3 Mémo rapide — Syntaxe Java


// Héritage
class Fille extends Mere { }

// Interface
class MaClasse extends Mere implements Interface1, Interface2 { }

// Classe abstraite
abstract class Abstraite {
public abstract void methodeAbstraite();
public void methodeConcrète() { /* ... */ }
}

// Comparable
class MonObj implements Comparable<MonObj> {
public int compareTo(MonObj autre) {
return [Link] - [Link]; // croissant
}
}

// Comparator externe
class MonComparateur implements Comparator<MonObj> {
public int compare(MonObj a, MonObj b) {
return [Link] - [Link]; // décroissant
}
}

// Collections utiles
[Link](liste); // Comparable
[Link](liste, monComparateur); // Comparator
[Link](liste, (a,b) -> ...); // Lambda (Java 8+)
[Link](0, [Link](11, [Link]())); // sous-liste des 11 premiers

8.4 Réponses aux questions théoriques fréquentes

Q : Comment représenter une réunion de sélectionneurs en un seul attribut ?


→ Utiliser List<Selectionneur> : comme Selectionneur est une interface implémentée à la fois par
Entraineur et Medecin, cette liste peut contenir les deux types grâce au polymorphisme.
private List<Selectionneur> selectionneurs = new ArrayList<>();
// Peut contenir Entraineur et Medecin indifféremment

Q : Pourquoi utiliser une Map<String, Personne> dans Equipe ?


→ La Map associe le CIN (clé unique) à la Personne (valeur). L'ajout/suppression par CIN devient
O(1) et garantit l'unicité des CINs sans parcourir toute la collection.

Q : Quelle est la différence entre ArrayList et LinkedList ?


→ ArrayList : tableau dynamique, accès par index O(1), insertion/suppression au milieu O(n).
LinkedList : liste doublement chainée, accès par index O(n), insertion/suppression O(1) si on a déjà
l'itérateur.

Q : Quand redéfinir hashCode() ?


→ Toujours quand on redéfinit equals(). Les HashSet/HashMap utilisent hashCode() pour trouver le
"seau" puis equals() pour comparer. Sans cohérence, deux objets égaux peuvent atterrir dans des
seaux différents → bugs silencieux.
Chapitre 9 — Mini-Projet Récapitulatif

Ce projet reprend tous les concepts du cours dans un exemple complet : une bibliothèque
universitaire.

// ══ Document (abstraite) ═════════════════════════════════


public abstract class Document {
private String isbn;
private String titre;
private int anneePublication;

public Document(String isbn, String titre, int annee) {


[Link] = isbn; [Link] = titre; [Link] = annee;
}

public abstract String getType();

@Override public String toString() {


return "[" + getType() + "] " + titre + " (" + anneePublication + ")";
}
public String getIsbn() { return isbn; }
public String getTitre() { return titre; }
}

// ══ Interface Empruntable ════════════════════════════════


public interface Empruntable {
boolean estDisponible();
void emprunter(String cin);
void retourner();
}

// ══ Livre ════════════════════════════════════════════════
public class Livre extends Document implements Empruntable, Comparable<Livre> {
private String auteur;
private String cinEmprunteur; // null si disponible

public Livre(String isbn, String titre, int annee, String auteur) {


super(isbn, titre, annee);
[Link] = auteur;
}

@Override public String getType() { return "Livre"; }

@Override public boolean estDisponible() { return cinEmprunteur == null; }


@Override public void emprunter(String cin) {
if (estDisponible()) cinEmprunteur = cin;
}
@Override public void retourner() { cinEmprunteur = null; }

// Tri alphabétique par titre


@Override public int compareTo(Livre autre) {
return [Link]().compareTo([Link]());
}
}

// ══ Bibliotheque ════════════════════════════════════════
public class Bibliotheque {
private Map<String, Document> catalogue = new HashMap<>();

public void ajouterDocument(Document d) {


[Link]([Link](), d);
}

public List<Document> rechercherParTitre(String motCle) {


List<Document> resultats = new ArrayList<>();
for (Document d : [Link]())
if ([Link]().contains(motCle)) [Link](d);
return resultats;
}

public List<Livre> getLivresDisponibles() {


List<Livre> disponibles = new ArrayList<>();
for (Document d : [Link]())
if (d instanceof Livre) {
Livre l = (Livre) d;
if ([Link]()) [Link](l);
}
[Link](disponibles); // tri alphabétique
return disponibles;
}
}

Concepts utilisés dans ce mini-projet


✅ Classe abstraite (Document)
✅ Interface (Empruntable)
✅ Héritage (Livre extends Document)
✅ Implémentation multiple (implements Empruntable, Comparable)
✅ Polymorphisme (catalogue Map<String, Document>)
✅ instanceof + downcasting
✅ Comparable + [Link]()
✅ Map pour accès O(1) par ISBN

Bon courage pour vos examens ! 🎓


Cours Java POO — ENIT — Mohamed Ramzi HADDAD

Vous aimerez peut-être aussi