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

BPOO

La programmation orientée objet (POO) répartit la résolution de problèmes sur des objets qui interagissent par messages, permettant l'encapsulation et l'héritage pour améliorer la réutilisabilité du code. Ce cours vise à approfondir les notions de POO en Java, à apprendre à programmer proprement et à introduire Swing. Les étudiants doivent participer activement, poser des questions et travailler sur des projets en équipe pour mettre en pratique les concepts appris.

Transféré par

mignamenoumariejean
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 PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
87 vues23 pages

BPOO

La programmation orientée objet (POO) répartit la résolution de problèmes sur des objets qui interagissent par messages, permettant l'encapsulation et l'héritage pour améliorer la réutilisabilité du code. Ce cours vise à approfondir les notions de POO en Java, à apprendre à programmer proprement et à introduire Swing. Les étudiants doivent participer activement, poser des questions et travailler sur des projets en équipe pour mettre en pratique les concepts appris.

Transféré par

mignamenoumariejean
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 PDF, TXT ou lisez en ligne sur Scribd

BASE DE LA PROGRAMATION ORIENTEE OBJET

Introduction
À la différence de la programmation impérative, un programme
écrit dans un langage objet répartit l’effort de résolution de problèmes sur
un ensemble d’objets collaborant par envoi de messages. Chaque objet se
décrit par un ensemble d’attributs (caractéristiques de l'objet) et un
ensemble de méthodes portant sur ces attributs (fonctionnalités de l'objet).
La POO résulte de la prise de conscience des problèmes posés par
l’industrie du logiciel ces dernières années en termes de complexité accrue
et de stabilité dégradée. L'objet solutionne certains de ces problèmes à
travers :
• l'encapsulation des attributs qui empêche toute modification
externe accidentelle
• l'héritage qui permet la ré utilisabilité du code
Il est inconséquent d’opposer la programmation impérative à l’OO car, in
fine, toute programmation des méthodes reste tributaire des mécanismes
de programmation procédurale et structurée. On y rencontre des
variables, des arguments, des boucles, des arguments de fonction, des
instructions conditionnelles, tout ce que l’on trouve classiquement dans
les boîtes à outils impératives.

Objectifs visés du cours :


 Découvrir/approfondir les notions de programmation objet
 Mise en œuvre des acquis de la programmation objet (Java)
 Apprendre à programmer "proprement"
 Introduction à Swing
Conseils pour mieux réussir Contrôle des connaissances

En TD c’est VOUS qui travaillez =⇒ Pas de correction à


Contrôle Continu
copier/coller =⇒ analyse/amélioration de VOTRE solution
- des TPs à rendre régulièrement
- un Projet
• N’apprenez pas par cœur, ça ne sert à rien ! - par équipe de 4 (les étudiants doivent être du même groupe)
- objectif : mettre en pratique les notions de POO
• Posez des questions en amphi (oui, vous pouvez toujours le faire)
- période de réalisation : début avril à début mai
• Posez des questions en TD - note CC : 1
∗ TP + 2
∗ Projet
3 3
• Participez au forum du cours : https://piazza.com/class/kjifrxy1n0i3xa Examen
- formuler une question permet de mieux comprendre le problème - Durée de 3 heures
- généralement votre question intéresse plusieurs étudiants, ils n’ont juste - questions de cours + exercices
pas osé la poser... - documents autorisés : feuille A4 manuscrite recto-verso
- sur 5 enseignants, vous trouverez toujours un qui répondra rapidement
- souvent les étudiants répondent aux questions Note finale : 50% CC et 50% examen
- très pratique pour le travail en distanciel

5 / 56 6 / 56

Les outils Un peu de biblio


H. Schildt. Java : A Beginner’s Guide, 7th Edition
• Langage de programmation : Java version ≥11 McGraw-Hill : 2017 (6ème édition pour Java 8 disponible en
• La notation UML (vue en cours de Conception Orientée Objets) ligne gratuitement)

• IDE : IntelliJ IDEA ou autre (Eclipse, NetBeans, etc.) J. Blosch. Effective Java, 3rd Edition
Addison-Wesley Professional : 2018.
• Les tests : JUnit (version 5)
R.C. Martin.
• Versioning : Git et GitHub
Clean Code - A Handbook of Agile Software Craftmanship
Prentice Hall : 2008.
...et pour commencer, au moins quelques principes de
E. Freeman, E. Robson, B. Bates, K. Sierra.
programmation :
Head First - Design Patterns (régulièrement mis à jour)
KISS - Keep It Simple and Stupid O’Reilly : 2014.
YAGNI - You Ain’t Gonna’ Need It
DRY - Don’t Repeat Yourself Pensez à consulter régulièrement la documentation officielle Java :
https://docs.oracle.com/en/java/javase/11/docs/api/
index.html
7 / 56 8 / 56
Java Pourquoi Java dans ce cours ?
Java est un langage de programmation
• Simple à prendre en main
• langage de haut niveau, objet, portable, ...
- l’API officielle très riche et assez fiable,
• langage pseudocompilé (bytecode) exécuté par la JVM - langage compilé et robuste :
langage fortement typé
avec un mécanisme puissant de gestion d’exceptions
- pas très verbeux
- gestion automatique de la mémoire : 
Java est aussi une plateforme utilisation implicite des pointeurs (références)
plus de sécurité
le ramasse-miettes (garbage collector )
• plateforme portable (Write once, run anywhere)
• interface de programmation d’application (API) • framework de tests unitaires complet : JUnit
- Swing, AWT, JavaFX
• un des langages orientées objets les plus répandus au monde
- JDBC
- Réseau, HTTP, FTP
- IO, math, config, etc. Attention : ce cours aurait pu très bien avoir un autre langage
orientée objet comme support (C++, C#, Python, etc.)

9 / 56 10 / 56

Approches de programmation Objets - première immersion


Approche fonctionnelle
• Approche traditionnelle utilisant des procédures et des fonctions
Définition
• On identifie les fonctions nécessaires à l’obtention du résultat Un objet informatique définit une représentation simplifiée, une
• Les grands programmes sont décomposés en sous programmes abstraction d’une entité du monde réel.
- hiérarchie de fonctions et sous-fonctions
- approche descendante (Top-Down)
But recherché :
• mettre en avant les caractéristiques essentielles
Approche orientée objet • dissimuler les détails
1. On identifie les entités (objets) du système
2. Chaque objet possède un ensemble de compétences (fonctions) Exemple d’objet Etudiant (ou abstraction Etudiant)
• description : nr. d’étudiant, sexe, année d’inscription, notes en
3. On cherche à faire collaborer ces objets pour qu’ils
accomplissent la tâche voulue : cours, absences. . .
• les objets interagissent en s’envoyant des messages (appels de • compétences (ou services) : apprendre, s’inscrire, passer les
fonctions) examens. . .
• un message dit quoi faire, mais non comment : chaque objet est
responsable de son fonctionnement interne

11 / 56 12 / 56
Objets - première immersion Classe vs Objets
Définition (une autre)
Objet = identité + état + comportement
Définition
Exemple d’objet Voiture : Une classe est une description abstraite d’un ensemble d’objets ”de
• Identité : numéro d’identification ou code-barres etc. même nature”. Ces objets sont des instances de cette classe.
• État : marque, modèle, couleur, vitesse. . .
• La classe est un ”modèle” pour la création de nouveaux objets.
• Services rendus par l’objet : Démarrer, Arrêter, Accélérer,
Freiner, Climatiser, . . . • ”Contrat” garantissant les compétences de ses objets.

Lorsqu’on utilise objet, on n’a pas à connaı̂tre/comprendre son Exemples :


fonctionnement interne : • L’objet philippe est une instance de la classe Humain.
• à priori on ne connaı̂t pas les composantes d’une voiture. . . • L’objet renaultQuatreL est une instance de la classe Voiture.
• à priori on ne connaı̂t pas les mécanismes internes de la voiture • L’objet bases Prog Objet est une instance de la classe Cours.
(comment elle accélère, la façon dont elle freine, etc). . .
• . . . mais on peut utiliser la voiture en lui demandant ses
services !
13 / 56 14 / 56

Classe vs Objet – exemples Classe vs Objet – parallèle avec les BD


Illustration d’une classe graphiquement (en UML) :
Voiture En Java :
attributs -marque: string
-modele: string En UML : class Point2D {
-dateFabrication: Date private double x;
private double y;
+demarrer(): void Point2D
+arreter(): void
public void deplacer(double x1, double y1) {
-x: double /* Le code des méthodes à écrire
Operations -y: double au moment où on programme */
}
+deplacer(x1: double, y1: double): void
}
La même classe écrite en Java :
class Voiture {
private String marque;
private String modele; En base de données :
private LocalDate dateFabrication;
ID x y • Table ≈ Classe
public void demarrer() { 0 1.2 -0.6
}
/* Le code à écrire au moment où on programme */
1 0.5 0.5 • Chaque ligne est un objet (instance de la classe)
2 0 1
public void arreter() {
3 3.4 0.3
• Important : pas d’équivalent des méthodes
/* Le code à écrire au moment où on programme */
}

15 / 56 16 / 56
Construction des objets Construction par défaut
Dans un programme Java, toute variable doit être initialisée avant Si le développeur n’a écrit aucun constructeur, alors le compilateur
d’être utilisée. fournit un constructeur sans argument qui consiste à initialiser tous
les champs avec leur valeur par défaut.
Pour les objets on parle de construction. class Point2D {
int x, y;
class Voiture { class Voiture { class Point2D {
private String marque; private String marque; public Point2D() {
int x, y;
private String modele; private String modele; x = 0;

public void demarrer() { // constructeur explicite


public String toString() {
return "[" + x + "," + y + "]";
= }
y = 0;

/* Le code de la fonction */ public Voiture(String uneMarque, String unModele) { }


} marque = uneMarque; public String toString() {
}
modele = unModele; return "[" + x + "," + y + "]";
public void arreter() { } }
/* Le code de la fonction */ }
} public void demarrer() {
/* Le code de la fonction */
} } À l’utilisation :
public void arreter() {
Point2D point = new Point2D();
/* Le code de la fonction */
System.out.println(point); // [0,0] s’affiche
}

L’écriture d’un constructeur explicite suspend le mécanisme de


// construction par défaut // construction explicite
Voiture renaultQuatreL = new Voiture(); Voiture renaultQuatreL = new Voiture("Renault", "QuatreL"); construction par défaut.
17 / 56 18 / 56

Exemple d’une application orientée objet en Java Un autre exemple


class Voiture {
private String marque; class Point2D { class Point2D {
private String modele;
private double x; private double x;
private LocalDate dateFabrication; private double y; private double y;

// le constructeur de la classe public Point2D(){ public Point2D(){


public Voiture(String uneMarque, String unModele) { x = 1; x = 1;
marque = uneMarque; y = 2; y = 2;
modele = unModele; } }
dateFabrication = LocalDate.now(); public void deplacer(double nouvX, double nouvY) { public void deplacer(double nouvX, double nouvY) {
} x = nouvX; x = Math.abs(nouvX);
y = nouvY; y = nouvY;
public void demarrer() { } }
/* Du code */
} } }

class App {
public void arreter() { public static void main(String args[]) {
/* Du code */
} // Création d’un point
} Point2D petitPoint = new Point2D();

// Utilisation du point créé


class ClassePrincipale { petitPoint.deplacer(2,3);

/* Méthode principale de l’application Java : le point d’entrée du programme */ petitPoint.deplacer(-6,4);


}
public static void main(String args[]) {
}
Voiture maVoiture = new Voiture("Renault", "QuatreL"); // Création d’un objet maVoiture
maVoiture.demarrer(); // Utilisation d’un service de l’objet
maVoiture.arreter(); // Utilisation d’un service de l’objet
} L’utilisation de l’objet petitPoint se fait de la même manière quelques
}
soient les changements du code de son fonctionnement interne.

19 / 56 20 / 56
Petite recap – vocabulaire Cycle de vie des objets
Temps

État initial état 1 état 2 état 3 État final


(Construction) (Destruction)

Pour une classe :


Dans une application, le cycle de vie d’un objet a 3 phases :
• attribut = champs ≈ variable globale
1. Création de l’objet en faisant appel au constructeur
• fonction = procédure = méthode • Réservation d’un bloc mémoire correspondant à l’objet
• Initialisation des ses attributs : état initial
• construction = instanciation ≈ initialisation ”propre”
2. L’évolution de l’objet où il peut changer d’états à plusieurs
reprises
Lorsqu’un objet o d’une classe A est construit, on dit que o est une
instance de la classe A. 3. Destruction de l’objet (implicite en Java)
• invoquée lorsque l’objet n’a plus vocation d’être utilisé
• libération de l’espace mémoire utilisé par l’objet
• se fait ”automatiquement” dans certains langage (dont Java), il
suffit ”d’oublier” l’objet – Garbage Collector ou ramasse-miettes

21 / 56 22 / 56

Cycle de vie des objets : exemple en Java Destruction des objets


import java.awt.Color;

public class Voiture {


private String modele; • En Java, le Garbage Collector (ramasse-miettes) est
private Color couleur;
private double prix; import java.util.ArrayList; responsable de la destruction des objets inutiles.
import java.awt.Color;
public Voiture(String modele, double prix) {
this.modele = modele; public class Concessionnaire {
this.prix = prix;
this.couleur = Color.WHITE;
private String nom;
private double soldeCompte;
• Le Garbage Collector se déclenche en temps ”presque masqué”,
} private ArrayList<Voiture> mesVoitures;

public void setCouleur(Color couleur) {


lorsque la mémoire manque ou la machine virtuelle est oisive.
public Concessionnaire(String nom, double solde) {
this.couleur = couleur; this.nom = nom;
} soldeCompte = solde;

public void setPrix(double prix) { }


mesVoitures = new ArrayList<>(); • Principe de fonctionnement :
this.prix = prix;
} public void commanderVoiture(){ 1. marquage des cellules mémoires occupées par des objets
Voiture v = new Voiture("SuperCitadine", 0);
public double getPrix() { v.setCouleur(Color.RED); // changement d’état accessibles
return prix; v.setPrix(10255); // changement d’état

}
}
}
mesVoitures.add(v); 2. tout ce qui est non marqué est désigné ”garbage”
public class App { public void vendreVoiture(){ 3. désignation des cellules mémoires non marquées comme
public static void main(String args[]) { Voiture v = mesVoitures.get(0);
Concessionnaire treNaud = new Concessionnaire("treNaud", 125360); soldeCompte += v.getPrix(); disponibles à la réutilisation (on peut écraser leur contenu)
// méthode où un objet de type Voiture sera créé // on va enlever de la liste la première
treNaud.commanderVoiture(); // occurrence de la référence v

treNaud.vendreVoiture(); }
mesVoitures.remove(v);
• Important : dès lors que l’objet n’est plus accessible dans le
}
/* À la fin de l’exécution de la méthode vendreVoiture(), un objet code, il faut supposer qu’il est détruit.
de type Voiture ne sera plus accessible. Donc, l’espace mémoire
qu’il occupe sera rendu disponbile par le Garbage Collector. */
}
}
23 / 56 24 / 56
Classe–Type–Objet Typage Java
Définition
Un type de données définit : En Java toutes les données sont typées. Il y a deux sortes de types :
• un domaine de valeurs (associé aux données de ce type) • types primitifs (prédéfinis)
• un ensemble d’opérations applicables aux données de ce type • types objets (référence)

int n = 40; // n est de type int type primitif taille en octets valeur par défaut
n = n + 2; // l’opération + est applicable sur les int boolean 1 bit false Accès par valeur pour les types primitifs :
boolean b = true; // b est de type boolean byte 1 0
b = true/3: // opération non-valide car la division n’est pas applicable sur les boolean short 2 0 int x, y;
int 4 0 x = 2;
Une classe définit en fait un type d’objets : long 8 0 y = 3;
float 4 0.0
• un ensemble de propriétés (des attributs) double 8 0.0 // on compare la valeur de x à la valeur de y
x == y;
char 2 ’\u0000’
• un ensemble de comportements applicables (des opérations)
Voiture L’accès aux types objets se fait par référence :
attributs -marque: string
-modele: string Voiture v; // v est de type Voiture
Voiture x, y; // deux objets de type Voiture
-dateFabrication: Date x = new Voiture();
v.demarrer(); // méthode applicable sur un type Voiture
+demarrer(): void y = new Voiture();
+arreter(): void x == y; // on compare les adresses mémoire de x et de y
v.manger(); // méthode non-applicable sur un type Voiture
Operations

25 / 56 26 / 56

Types référence (objet) Types primitifs vs types référence : Autoboxing


• En Java pour chaque type primitif il existe un type objet
• Hormis les types primitifs, tous les types en Java sont des correspondant appelée type enveloppe (ou wrapper type)
objets. exemple : Integer pour int, Boolean pour boolean, etc.

• Les types génériques ne peuvent pas être des types primitifs :


• Exemples des types objets :
List<int> liste = new ArrayList<int>(); // interdit !
- String
- Tableaux, listes (toutes les structures de données) • Par exemple, pour ajouter des int dans une collection (ici
- Les énumérations
List), il faut utiliser la classe d’emballage Integer :
- Toutes les autres classes pré-définies en Java ou créées par
l’utilisateur List<Integer> liste = new LinkedList<Integer>();
int nombre = 5;
liste.add(new Integer(nombre)); //emballage (boxing)
• La valeur par défaut des types objets est null : liste.add(nombre); //emballage automatique (autoboxing)
int v1 = liste.get(0); // déballage automatique (auto-unboxing)
Voiture v; int v2 = liste.get(1); // déballage automatique (auto-unboxing)
System.out.println(v); // affiche "null" Integer v3 = liste.get(0);
Integer v4 = liste.get(1);
int v5 = v4.intValue(); // déballage

27 / 56 28 / 56
Utilité des types primitifs Typage Java : représentation en mémoire
L’esprit de la programmation orientée objet est que tout est objet.
Comment une variable x est représentée en mémoire ?
à quoi bon avoir créé des types primitifs ? ? ?
Cas 1 type primitif : x = valeur
Que fait-il ? @i

@j valeur
class App {
public static void main(String args[]) { x @k

@l
Integer somme = 0;
for (int i = 0; i < 100000; i++)
somme += i; Cas 2 type référence : x = objet

System.out.println(somme); @i

} @j @n objet
@n
} x @k

@l

Inconvénients ?
29 / 56 30 / 56

Accès par valeur vs accès par référence Passage de paramètres


Compte c1 = new Compte("Tartempion", "Riri");
int x = 10, y = 20;
c1.rechargerCompte(100); Dans les langages de programmation modernes, il existe
x = y;
Compte c2 = new Compte("Barbanchu", "Fifi");
System.out.println(x + ", "+y); // resultat ?
c2.rechargerCompte(392);
essentiellement deux modes de passage de paramètres :
y++;
Compte c3 = new Compte("Duchmolle", "LouLou");
System.out.println(x + ", "+y); // resultat ?
System.out.println(c1); // resultat ? Passage par valeur
System.out.println(c2); // resultat ?
class Compte {
System.out.println(c3); // resultat ? C’est la valeur de la variable au moment de l’appel qui est utilisée.
private String nom, prenom;
c1 = c2; Autrement dit, c’est une copie du contenu de cette variable au
private double soldeCompte;
System.out.println(c1); // resultat ? moment de l’appel qui est passée à la fonction.
System.out.println(c2); // resultat ?
public Compte(String n, String p) {
nom = n; prenom = p;
soldeCompte = 0;
c1.rechargerCompte(55);
⇒ La variable initiale n’est pas accessible (donc non-modifiable)
}
System.out.println(c1); // resultat ?
System.out.println(c2); // resultat ?
par la fonction appelée.
public void rechargerCompte(double somme) {
soldeCompte += somme;
c2 = c3;
}
Passage par adresse
System.out.println(c1); // resultat ?
// méthode spécifique Java pour l’affichage
System.out.println(c2); // resultat ?
System.out.println(c3); // resultat ?
C’est l’adresse de la variable placée en paramètre lors de l’appel qui
public String toString() {
return "[" + prenom +
c3 = c1;
est utilisée.
","+nom+","+soldeCompte +"]";
}
System.out.println(c1); // resultat ?
}
System.out.println(c2); // resultat ? ⇒ La variable initiale est accessible (et donc modifiable) par la
System.out.println(c3); // resultat ?
fonction appelée
31 / 56 32 / 56
Passage de paramètres en Java Passage de paramètres en Java
Attention aux paramètres de type objet !
En Java, le passage de paramètres se fait toujours par valeur

Autrement dit, la méthode manipule une copie du contenu de la class Voiture {


String modele; class Usine1 {
variable passée en paramètre. public void customizer(Voiture v) {
public Voiture(String m) { v = new Voiture ("berline");
1. si la variable est de type primitif : son contenu est une valeur effective, modele = m; }
} }
donc c’est en quelque sorte une ”vraie” copie
public void changerModele(String m) {
public void toto() { public void foo(int v) { modele = m;
int x = 10; v = 30; } class Usine2 {
System.out.println(x); // 10 // v est une copie de la variable passée en paramètre, public void customizer(Voiture v) {
foo(x); // à la sortie de la fonction, les modifications public String toString() { v.changerModele("berline")
System.out.println(x); // 10 // sur cette copie seront oubliées return "La voiture est une "+modele; }
} } } }
}

2. si la variable est de type référence, alors la méthode manipule une class App { class App {
/* Du code ici */ /* Du code ici */
copie de l’adresse (indiquant où est situé l’objet concerné). Donc : public static void main(String args[]) { public static void main(String args[]) {
Voiture maCaisse = new Voiture("cabriolet"); Voiture maCaisse = new Voiture("cabriolet");
cette adresse est non-modifiable (car passage par valeur) mais System.out.println(maCaisse); // resultat ? System.out.println(maCaisse); // resultat ?
Usine1 u1 = new Usine1(); Usine2 u2 = new Usine2();
l’objet référencé, lui, est accessible, et donc modifiable à travers son u1.customizer(maCaisse);
System.out.println(maCaisse); // resultat ?
u2.cusomizer(maCaisse);
System.out.println(maCaisse); // resultat ?
interface publique. }
}
}
}

33 / 56 34 / 56

Référence this Collaboration entre constructeurs


Une classe peut avoir plusieurs constructeurs :
En Java, le mot clef this permet de référencer l’objet courant.
class Compte {
private String nom, prenom;
private double soldeCompte;
class Compte { class Compte {
public Compte(String nom) {
private String nom, prenom; private String nom, prenom; this.nom = nom;
private double soldeCompte; private double soldeCompte; }

public Compte(String n, String p) { public Compte(String nom, String prenom) { public Compte(String nom, String prenom) {
nom = n; this.nom = nom; this(nom); // appel du constructeur Compte(String)
prenom = p; this.prenom = prenom; this.prenom = prenom;
soldeCompte = 0; soldeCompte = 0; }
} }
public Compte(String nom, String prenom, double soldeCompte) {
public void rechargerCompte(double somme) { public void rechargerCompte(double soldeCompte) { this(nom, prenom); // appel du constructeur Compte(String, String)
soldeCompte = somme; this.soldeCompte = soldeCompte; this.soldeCompte = soldeCompte;
} } }

// méthode spécifique Java pour l’affichage // méthode spécifique Java pour l’affichage public void rechargerCompte(double soldeCompte) {
public String toString() { public String toString() { this.soldeCompte = soldeCompte;
return "[" + prenom + return "[" + prenom + }
","+nom+","+soldeCompte +"]"; ","+nom+","+soldeCompte +"]"; }
} }

} }
Pensez à faire collaborer les constructeurs pour éviter la duplication
de code !
35 / 56 36 / 56
Environnement Java Environnement Java - les packages
De point de vue physique un programme Java est :
• un ensemble de fichiers sources .java Remarque
• un ensemble de fichiers compilés .class (le En Java chaque classe appartient nécessairement à un package.
byte-code) correspondants aux sources
• le tout organisé dans des répertoires : • les packages permettent un découpage de l’espace de nommage
- pensez à séparer le byte-code des sources en plusieurs sous-espaces de noms.
• un package est un ensemble cohérent de classes pouvant être
De point de vue logique un programme Java est un ensemble de importées toutes ensembles comme individuellement.
classes organisées dans des packages (ou paquetages).
• package par défaut : unnamed (son utilisation est fortement
déconseillée)
• le nom complet d’une classe (Fully Qualified Class Name ou
fichier .class FQCN) est constitué du nom du package auquel elle appartient
suivi de son nom. Par exemple :
classe Java
java.util.ArrayList // la classe ArrayList située dans le package java.util

37 / 56 38 / 56

Environnement Java - les packages Packages : illustration


// paquetage où est située la classe
// paquetage où est située la classe
package drawingElements;
package drawingElements
// classes importées dans le paquetage java.util
class Point2D {
import java.util.List;
import java.util.ArrayList;
private double x;
private double y;
class Courbe {
public Point2D(int x, int y){
List<Point2D> listeDePoints;
this.x = x;
this.y = y;
public Courbe(Point2D pointInitial){
}
listeDePoints = new ArrayList<>();
listeDePoints.add(pointInitial);
public void deplacer(double nouvX, double nouvY) {
x = nouvX;
y = nouvY;
}
−→
public void etendre(Point2D nouveauPoint) {
}
listeDePoints.add(nouveauPoint);
}
}
}

• L’instruction ”package nomDuPackage” doit être la première du fichier.


Elle n’est pas obligatoire si le package est celui par défaut.
• Si deux classes A et B sont dans le même package, alors pas besoin
d’importer quoique ce soit dans B pour accéder à la classe A.

39 / 56 40 / 56
Encapsulation Encapsulation – visibilité
Une classe a deux aspects :
En Java, il y a 4 niveaux de visibilité :
1. son interface : vue externe (ne pas confondre avec le mot-clé ”interface” en Java)
class Toto {
2. son corps : implémentation des méthodes et des attributs private int u; // seules les méthodes de la classe Toto y ont accès

int v; // visibilité par défaut : accessible aux membres de la classe Toto


Définition // et de toutes les classes situées dans le m^eme paquetage

L’encapsulation est un principe de conception et de programmation protected int x; // accessible aux membres de la classe Toto, de ses sous-classes
//et de toutes les classes situées dans le m^
eme paquetage
consistant à distinguer l’interface et le corps d’une classe. public int y; // accessible aux membres de toutes les classes
}
• un mécanisme de visibilité permet de contrôler les accès au
corps d’un objet
Remarques :
• seules les méthodes doivent pouvoir manipuler l’état interne de
La notion de sous-classe sera
l’objet et servent à la communication inter-objets vue ultérieurement.
Principe fondamental de la POO Ici ClasseA et ClasseB ont
L’utilisateur/programmeur ne connaı̂t que l’interface de l’objet. les mêmes accès aux
L’implémentation de sa classe est masquée et non accessible à membres de la classe Toto
l’utilisateur.
41 / 56 42 / 56

Encapsulation : quelques conseils Membres et méthodes static


• À priori, tous les attributs doivent être privés. L’utilisation de • Un attribut static est partagé par toutes les instances de la
toute autre visibilité doit être argumentée. classe (valeur unique pour toutes ses instances)
À votre avis, pourquoi ? public class Produit {
private int nrISBN;
private double prix;
private boolean estDispo;
Exemple d’utilisation :
• Si besoin d’accéder à un attribut à partir d’une autre classe :
private static double marge = 2.5; public class Magasin {
créer un accesseur (ou getter en anglais). public static void main(String args[]) {
public Produit(int nrISBN, double prix) { Produit tablette = new Produit(859587, 200);
this.nrISBN = nrISBN; this.prix = prix; Produit pc = new Produit(465756, 952);
• Si besoin d’accéder à un attribut à partir d’une autre classe : }
estDispo = true;
// affiche 2.5
System.out.println(Produit.getMarge());
créer un modifieur (ou setter en anglais). public void setPrix(double prix){
this.prix = prix; // on modifie la marge pour tous les produits
} Produit.setMarge(3.6);
• Créer des accesseurs/modifieurs alors que l’on n’en a pas public void reserver() { // affiche 3.6
forcément besoin est un signe de non-respect du principe }
estDispo = false;
}
System.out.println(Produit.getMarge());

d’encapsulation. public static double getMarge() {


}

return marge;
}
Pensez au principe YAGNI (You Ain’t Gonna’ Need It) :
public static void setMarge(double v) {
protégez-vous de vos propres bêtises (et de celles de futurs marge = v; tablette.setMarge(3.6); // instruction qui fonctionne
} // mais qui est INTERDITE
collaborateurs) }

43 / 56 44 / 56
Membres et méthodes static Mot-clef final
Être déclaré en static est une contrainte très forte : Pseudo-définition
• aucune dynamique : pas de possibilité d’avoir une valeur
Une entité final ne peut être instanciée qu’une seule fois.
d’attribut différente pour chaque objet de même type
• pour une variable ou un attribut : une fois la valeur affectée,
• les méthodes static peuvent manipuler que des attributs
elle ne pourra plus être modifiée. Exemple :
static. Erreur du débutant : déclarer tout en static, comme
ça on n’en parle plus ! /
public void test1() { public void test2() {
final int x = 10; final Voiture v = new Voiture("berline");
v.setCouleur(Color.BLACK); // fonctionne car on change l’état
System.out.println(x); // affiche 10 // mais pas l’objet lui-m^
eme
• la méthode main(String) de la classe principale est static
x = 25; // ERREUR de compilation v = new Voiture("berline"); // ERREUR de compilation
car c’est le point d’entrée du programme x++; // ERREUR de compilation v = new Voiture("cabriolet"); // ERREUR de compilation
} }
• on utilise souvent la clause static final pour déclarer des
• si la variable/attribut est une référence vers un objet, alors on
constantes :
peut modifier son état interne (à travers ses méthodes), mais la
public static final double PI = 3.14 ;
référence de l’objet sera la même
Moralité • les classes et les méthodes peuvent aussi être déclarées final
L’utilisation des membres static doit être justifiée. - classe final : ne peut pas être ”sous-classée” (à voir plus tard dans le cours)
- méthode final : ne peut pas être ”redéfinie” dans une ”sous-classe”
45 / 56 46 / 56

Type énuméré Écrire du code : règles de bon sens


Parfois il est utile d’utiliser un ensemble prédéfini de constantes : public class P {
• les points cardinaux : nord, est, sud, ouest private C c;
private List<A> cnt = new ArrayList<A>();

• les 7 jours de la semaine public P(C c){


this.c = c;
}
• les marges dans un document public void m(A a, int q) {
for (int i = 0; i < q; i++) {
cnt.add(a);
On utilise les types énumérés dès lors que le domaine de valeur est Qu’est-ce que c’est ? ? ? −→ }
}
un ensemble fini et relativement petit de constantes :
public int ct() {
public enum Jour { int t = 0;
public enum Coordonnee { public enum Margin { for (A a : cnt) {
LUNDI, MARDI, MERCREDI, JEUDI,
NORD, EST, SUD, OUEST TOP, RIGHT, BOTTOM, LEFT t += a.getP();
VENDREDI, SAMEDI, DIMANCHE
} } }
}
return t;
}
}
La déclaration enum définit une classe et donc on peut y ajouter
des méthodes et autres champs.
• programme claire ?
Avantage principal : des noms claires/explicites à l’utilisation
• comprend-on son but ? ou a-t-il besoin des commentaires
Pour plus d’infos : https://docs.oracle.com/javase/ supplémentaires ?
tutorial/java/javaOO/enum.html
47 / 56 48 / 56
Écrire du code : règles de bon sens Écrire du code : règles de bon sens
Règle d’or • 80% de la vie d’une application c’est de la maintenance et le
Donner des noms simples et descriptifs aux classes, attributs et méthodes. code ne sera pas forcément maintenu par le même développeur
• Le lecteur doit comprendre le sens de votre code... sans avoir
public class P {
private C c;
public class Panier { à comprendre les subtilités techniques/algorithmiques
private Client client;
private List<A> cnt = new
private List<Article> contenu = new ArrayList<Article>();
ArrayList<A>();
public Panier(Client client) {
• Essayez de faire des fonctions courtes et simples (une seule
public P(C c){
this.c = c;
}
this.client = client; action à la fois)
}

public void m(A a, int q) {


public void ajouter(Article a, int quantite) {
for (int i=0; i<quantite; i++) {
• ”Don’t comment bad code – rewrite it !”
for (int i=0; i<q; i++) {
contenu.add(a);
}
cnt.add(a);
} B.W. Kernighan et P.J. Plaugher
}
}
• Testez, Relisez −→ Refactorisez (utilisez l’IDE)
public int calculerTotal() {
public int ct() {
int total = 0;
int t = 0;
for (A a: cnt) {
for (Article a: contenu) {
total += a.getPrix();
• Plus de conseils dans
t += a.getP();
}
}
return total;
Clean Code : A Handbook of Agile Software Craftsmanship de
return t;
}
}
}
Robert C. Martin
}
Respectez les conventions de nommage du langage.
49 / 56 50 / 56

Conventions de nommage Java - sémantique Conventions de nommage Java - lexique


• package
Les conventions ne sont pas imposées par le compilateur, mais tout
- tout en minuscule avec les mots collés
le monde s’attend à ce qu’elles soient suivies. - les caractères autorisés sont alphanumériques (de a à z, de 0 à 9) et
• classe : peuvent contenir des points
- groupe nominal au singulier - ex : java.util, javafx.scene, fr.umontpellier.iut
- exemples : Client , Reservation , CompteEpargne - doit commencer par un nom de domaine (TLD) : com, edu, org, fr, etc.
• attribut et variable : • classe :
- groupe nominal singulier ou pluriel - 1ère lettre en majuscule
- des noms très courts uniquement pour les variables à la durée - mots attachés, avec majuscule aux premières lettres de chaque
de vie très courte (compteurs de boucle ou autre) - ex. : MaPetiteClasse, Voiture, ArrayList
- utiliser uniquement des caractères de l’alphabet [A-Z], [a-z], [0-9] • attribut, méthode et variable : comme pour une classe mais 1ère
• méthode : lettre en minuscule
- doit comporter un verbe (en général à l’infinitif) • constante (champ static final)
- fermer() , ajouterElement() , calculerSomme() , - tout en majuscule avec des ” ” entre les mots
getContenu() Fenetre.expand() vs fenetre.expand()
• anglais ou français ? À vous de choisir mais pas de mélange ! Pour la première expression il s’agit d’un appel à une méthode statique

51 / 56 52 / 56
Qu’en pensez-vous ?
import java.awt.Color;

public class Rectangle {


private int longueur, largeur;
private Color couleur;

public Rectangle(int longueur, int largeur, Color couleur) {


this.longueur = longueur;
this.largeur = largeur;
this.couleur = couleur;
}

public void changer(int x){


longueur = x;
}

// on augmente suivant la proportion, mais on ne diminue jamais


public void resize(int proportion){
if (proportion > 1){
longueur = longueur * proportion;
largeur = largeur * proportion;
}
}

public void changerCouleur(){ Ça fonctionne mais...


couleur = Color.RED;
}

public Color coloration(){


return couleur;
}
}

53 / 56 54 / 56

https://xkcd.com/1513/

55 / 56 56 / 56
Héritage : respect du contrat Héritage : exemple avec l’API Java
• l’héritage est une relation transitive de type ”EST UN” : si la En Java toutes les classes héritent d’une classe spéciale : Object
classe A hérite de la classe B et B hérite de la classe C, alors A Object
hérite aussi de C +toString(): void
+equals(o: Object): void
+hashCode(): int
• La sous-classe est liée par le ”contrat” de sa classe parente #finalize(): void
+getClass(): Class
- elle ne peut pas restreindre la visibilité d’une méthode de la
...
classe parente :
code OK code interdit à la compilation
public class B { public class A extends B {
public void maMethode(){ private void maMethode(){
String Number System
... Runtime Thread Class
... Throwable

// corps // corps
} }
} }

- elle ne peut pas ne pas hériter une méthode/attribut définie


Integer
... Double
ClasseEcriteParUtilisateur2 ... Exception

dans sa classe parente


ClasseEcriteParUtilisateur1

MALGRÉ TOUT ÇA la classe-fille n’a pas accès aux


Par respect du contrat d’ Object , toutes les classes possèdent les
méthodes/attributs privés de la classe mère.
méthodes d’ Object et héritent du comportement d’ Object .
5 6

Héritage : exemple simple Héritage : comment ça marche ?


public class Personnel { public class Enseignant extends Personnel { public class App {
private String nom; private int numero;
public static void main(String[] args) {

public void setNom(String nom) { public void attribuerNumero(int n) { // instanciation d’un objet de type Personnel en tant qu’Enseignant
this.nom = nom; numero = n; Personnel membre = new Enseignant();
} } membre.setNom("Toto");
} } // instanciation d’un objet de type Enseignant en tant qu’Enseignant
Enseignant prof = new Enseignant();
prof.setNom("Lolo"); // utilisation de la méthode publique héritée de Personnel
prof.attribuerNumero(10059392);
public class App {
}
public static void main(String[] args) { }

// instanciation d’un objet de type Personnel en tant qu’Enseignant


Personnel membre = new Enseignant();
• En Java le typage se fait statiquement : Personnel membre
membre.setNom("Toto");
• upcasting - instanciation d’un objet d’un type de base en tant
// instanciation d’un objet de type Enseignant en tant qu’Enseignant
Enseignant prof = new Enseignant(); que sous-type : membre = new Enseignant()
prof.setNom("Lolo"); // utilisation de la méthode publique héritée de Personnel
prof.attribuerNumero(10059392); • Une méthode spéciale dans la classe Object permet de
}
}
retrouver le type effectif de l’objet : getClass()
(vous devriez l’éviter dans 99% de cas)
7 8
Héritage et constructeurs Héritage et constructeurs : respect du contrat

public class Personnel { public class Enseignant extends Personnel {


La construction d’une instance de la sous-classe commence private String nom; private int numero;
toujours par la construction de sa partie héritée.
public Personnel(String nom) { // cette définition ne passe pas àla compilation
this.nom = nom; public Enseignant(int numero) {
} this.numero = numero;
• Si le constructeur de la classe mère est sans paramètres ou est }
par défaut, alors Java l’appelle ”artificiellement” } }

• Si un constructeur avec des paramètres est défini dans la classe


public class App {
mère, alors la sous-classe est forcée à avoir un constructeur
appelant un des constructeurs de la classe mère : public static void main(String[] args) {

Personnel perso = new Enseignant(10059392); // ne peut pas fonctionner


public class A { public class B extends A{
private int attribut;
public B(int valeur){ Enseignant ens = new Enseignant(10059392); // ne peut pas fonctionner
public A(int attribut){ super(valeur); // appel au constructeur de la classe mère
this.attribut = attribut; } }
}
} } }

9 10

Héritage et constructeurs : respect du contrat Mot-clé super vs this en Java


public class Personnel { public class Enseignant extends Personnel {
• Rappel : this est la référence vers l’objet courant. Cas d’utilisation :
private String nom; private int numero; - depuis un constructeur, appel d’un autre constructeur de la même classe
public Personnel(String nom) { public Enseignant(String nom, int numero) {
- accéder depuis une fonction à un attribut, ayant le même nom qu’une
this.nom = nom; super(nom); variable locale
} this.numero = numero; - passer la référence this en paramètre d’une fonction
}
} }
• Le mot-clé super permet d’accéder aux éléments de la classe mère la
plus proche dans la hiérarchie. Cas d’utilisation :
public class App { - pour appeler le constructeur de la classe mère
- pour accéder à une fonction de la classe mère
public static void main(String[] args) {
public class Enseignant extends Personnel {
Personnel perso = new Personnel("Fifi"); public class Personnel {
private int numero;
private String nom;
public void attribuerNumero(int n) {
Personnel perso = new Enseignant("Toto",10059392); public void setNom(String nom) {
numero = n;
this.nom = nom;
}
}
Enseignant ens = new Enseignant("Lolo", 10059392);
public void travailler() {
public void travailler() {
// appel de la méthode de la super-classe
} System.out.println("Personnel qui travaille");
super.travailler();
} }
System.out.println("Enseignant qui travaille");
}
}
}

11 12
Polymorphisme Polymorphisme : illustration
• parfois certaines méthodes de la classe mère nécessitent une public class FormeGeometrique {
private double centre;
// on suppose avoir défini les coordonnées de chaque point pour décrire la forme géometrique
certaine adaptation, il est donc possible des les redéfinir.
public void calculerSurface() {
// calcul intégral en utilisant les coordonnées
FormeGeometrique }
-centre: Point }
+calculerSurface()
public class Rectangle extends FormeGeometrique { public class Cercle extends FormeGeometrique {
private double hauteur, largeur; private double rayon;

public void calculerSurface() { public void calculerSurface() {


double resultat = hauteur * largeur; double resultat = Math.PI * rayon * rayon;
} }
} }
Rectangle Trapeze
Cercle
-hauteur: double -grandeBase: double
-rayon: double public class ClasseCliente {
-longueur: double -petiteBase: double public static void main(String[] args) {
+calculerSurface() -hauteur: double
+calculerSurface() FormeGeometrique forme = new FormeGeometrique();
+calculerSurface() forme.calculerSurface(); // la méthode de calcul générale

forme = new Cercle();


• Ici, lorsque l’on invoque la méthode calculerSurface() sur forme.calculerSurface(); // la méthode de calcul de Cercle

un objet de type Cercle , c’est la méthode de Cercle qui forme = new Rectangle();
forme.calculerSurface(); // la méthode de calcul de Rectangle
sera invoquée (et pas celle de la classe mère). }
}

13 14

Polymorphisme Polymorphisme : surcharge


Poly = plusieurs, morphisme = forme :
public class Etudiant {
private ArrayList<Double> notes = new ArrayList<>();
Définition - Polymorphisme
public void ajouterNote(double note) { notes.add(note); }
• Propriété d’un élément de pouvoir se présenter sous plusieurs
public double getMoyenne(){
formes double moyenne = 0;
for (Double d : notes) {
moyenne += d;
• Capacité donnée à une même opération de s’effectuer }
return moyenne / notes.size()
différemment suivant le contexte de la classe où elle se trouve }

// méthode surchargée avec des paramètres différents


public double getMoyenne(double malusAbsence){
Dans le cas des figures géométriques, la fonction return getMoyenne() - malusAbsence;
}
calculerSurface() est une fonction polymorphe. }

Le polymorphisme est réalisable grâce à la Liaison Dynamique : • la surcharge d’une méthode a lieu lorsqu’on définit une nouvelle
Liaison dynamique méthode ayant le même nom, mais avec :
1. un nombre différents de paramètres et sinon,
Mécanisme permettant que la définition d’une méthode soit décidée au 2. les types de paramètres différents dans l’ordre (de gauche à
moment de l’exécution de celle-ci (et non à la compilation). droite)
=⇒ Introspection de type • cas que vous avez déjà vu : la surcharge du constructeur
15 16
Polymorphisme : exemples en Java equals(Object o) et hashCode()
Par défaut dans Object la méthode equals(Object o) fait la comparaison
L’annotation @Override indique au compilateur qu’on est en train de la plus ”naı̈ve” :
redéfinir une méthode de la classe parente
public class Object {
=⇒ s’il y a incohérence (erreur dans le nom, ou paramètres), le // du code de Object ici ...
compilateur va le signaler par une erreur public boolean equals(Object obj) {
return this == obj;
La classe Object possède plusieurs méthodes pratiques mais trois d’entre }
}
elles souvent sont à redéfinir :
• int hashCode() affecte un code ”pseudo-unique” à this afin de La situation est similaire pour hashCode() : typiquement l’adresse de this
est convertie en un entier (mais ça dépend de la JVM...)
permettre de l’identifier numériquement
• String toString() : une chaı̂ne de caractères censée décrire l’objet Pensez toujours à redéfinir ces deux fonctions en même temps
dans vos classes afin de respecter le contrat de Object :
par défaut : nom de la classe + @ + hash code obtenu à partir des
valeurs de chaque attribut de l’objet −→ peu lisible • equals(Object o) définit une relation d’équivalence
• si l’état de l’objet n’est pas modifié alors plusieurs appels à
• boolean equals(Object o) compare this à o de façon à
hashCode() retournent la même valeur
garantir une relation d’équivalence
• si les hash codes sont différents alors equals(0bject o)
retourne false (l’inverse n’est pas nécessairement vrai)
17 18

equals(Object o) et hashCode() : exemple Héritage : classe abstraite


Pensez à vous faire aider par l’IDE en générant ces deux méthodes Des objets de types différents peuvent avoir quelque chose en
et en adaptant le code obtenu. commun, mais ce quelque chose ne peut pas exister de manière
indépendante.
import java.util.Objects;
Exemple : un objet de type Humain est trop abstrait pour être
public class Employe {
private String nrINSEE, nom; instancié dans un système de gestion de personnel...
private int echelon;
private double base, nbHeures;
public abstract class Humain {
@Override
public boolean equals(Object o) { private String nom; public class Femme extends Humain {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; public Humain(String nom) { // obligation de définir un constructeur invoquant
Employe employe = (Employe) o; this.nom = nom; // le constructeur explicite de la classe mère
return echelon == employe.echelon && } public Femme(String nom) {
employe.base==base && super(nom);
employe.nbHeures== nbHeures && public String toString(){ }
nrINSEE.equals(employe.nrINSEE) && return "mon nom c’est : " + nom;
nom.equals(employe.nom); } }
// la classe String de Java a déjà redéfini son equals(Object o) - utilisez-le !
} }

@Override
public int hashCode() { Humain h1 = null; // On déclare l’objet de type Humain
return Objects.hash(nrINSEE, nom, echelon, base, nbHeures); Humain h2 = new Femme("Toto"); // On l’instancie avec un type concret
// on peut choisir sa propre fonction de hachage System.out.println(h2); // affiche "mon nom c’est : Toto"
} Humain h3 = new Humain(); // ERREUR de compilation

19 20
Classe abstraite Classe abstraite : illustration en Java
Définition public abstract class Medecin {
private String nom;
Une classe abstraite est une classe qui ne peut pas être instanciée. private int numeroID; «abstract»
Medecin
public void ecrireOrdonance() { /* du code ici */ } -nom: String
-numeroId: int
- sert uniquement de super classe à d’autres classes public void prendreTension() { /* du code ici */ } +ecrireOrdonance()
+prendreTension()
public abstract void soigner(); // méthode abstraite «abstract»+soigner()
- peut contenir des méthodes abstraites }

- ses sous-classes doivent définir toutes les méthodes abstraites public class Chirurgien extends Medecin {
private String scalpel;
(ou être abstraites elles-mêmes) public void soigner() { Generaliste Chirurgien Ophtalmologue
System.out.println("J’utilise un " + -stethoscope -scalpel -refracteur
«abstract» scalpel + " et j’opére");
+soigner() +soigner() +soigner()
Medecin }
}
-nom: String
Opérations -NumeroId: Integer
"normales" +ecrireOrdonance() public class Generaliste extends Medecin {
+prendreTension() private String stethoscope;
«abstract»+soigner() public void soigner() { System.out.println("J’utilise un " + stethoscope + " et je décide le soin"); }
}

public class Ophtalmologue extends Medecin {


Opération private String refracteur;
obligatoirement Generaliste Chirurgien Ophtalmologue public void soigner() { System.out.println("J’utilise un " + refracteur + " pour mesurer la vue"); }
redéfinie dans les }
sous-classes -stethoscope -scalpel -refracteur
+soigner() +soigner() +soigner()

21 22

Classe/méthode abstraite : à quoi bon ? Classe/méthode abstraite


Malgré le fait qu’un méthode soit abstraite, on peut l’utiliser dans la
Important : Dès qu’une méthode est déclarée abstraite, la classe qui classe abstraite... et souvent c’est extrêmement utile :
la contient doit être déclarée abstraite. Pourquoi ? public abstract class Produit { public class Smartphone extends Produit {
private double fraisLivraison; private String marque;
private double marge;
Respect du contrat de la classe mère : toutes les classes filles // on ne sait pas vraiment calculer le prix private double taxeRecyclage;
public abstract double getPrix();
”concrètes” savent effectuer les opérations public Smartphone(String marque, double marge,
// mais on sait comment calculer la facture double taxeRecyclage) {
public double getPrixFacturé(){ this.marque = marque;
• méthode abstraite = méthode ”promise” ; dans notre exemple : }
return getPrix() + fraisLivraison; this.marge = marge;
this.taxeRecyclage = taxeRecyclage;
}
- tous les médecins doivent pouvoir ”soigner”... }
- mais chacun à sa façon public double getPrix() {
return taxeRecyclage + marge;
• méthode concrète (ordinaire) : public class Livre extends Produit { }
private String nom; }
- toutes les instances vont hériter son implémentation... private double royalties;

- et ça sera aux sous-classes de s’y conformer ou de la redéfinir public Livre(String nom, double royalties) { public class AppProduit {
this.royalties = royalties; public static void main(String[] args) {
this.nom = nom; Produit p1 = new Smartphone("Poire", 989.99, 10);
} Produit p2 = new Livre("Tom Sawyer", 35);
Quel est alors l’intérêt des classes abstraites sans méthodes System.out.println("p1 : " + p1.getPrixFacture() +
public double getPrix() { "..., cher pour ce que c’est...");
abstraites ? return royalties + 10; System.out.println("p2 : " + p2.getPrixFacture());
} }
} }

23 24
Interfaces en Java Exemple d’interface : java.util.List
Rappel
«interface»
Classe ≈ nom + attributs + opérations List
+add()
+remove()
+contains(): boolean
+isEmpty(): boolean
• Une interface Java est équivalente à une classe «interface»
MonInterface +size(): int

qui n’a pas d’attributs et où toutes les méthodes ...


sont abstraites.
A
• interface ≈ classe ”totalement” abstraite
LinkedList Vector ArrayList
public class A implements MonInterface {
public interface MonInterface {
public int methodeSansAttributs() {
// implémentation concrète ici
public int methodeSansAttributs();
} • Une List en tant que telle est purement abstraite (rien ne
public void methodeAvecAttributs(int x);
public int methodeAvecAttributs(int x) {
// implémentation concrète ici
peut être défini à l’intérieur)
}
}
} • Mais les différentes implémentations de List doivent
respecter le contrat de List i.e. fournir une implémentation
Dans cet exemple on dit que A implémente l’interface
de toutes les méthodes imposées par List
MonInterface (ou encore, A est une réalisation de l’interface
MonInterface ) 25 26

Exemple d’interface : java.lang.Comparable Interface Comparable : illustration


TypeT public class Ville implements Comparable<Ville> {
«interface» private String nom;
Comparable Tous les objets de type TypeT Définition dans l’API Java : private Integer codePostal;
réalisant cette interface pourront être private Integer population;
+compareTo(obj: TypeT): int comparés
public Ville(String n, int cp, int p) {
// l’interface àimplémenter par toute nom = n;
// classe T destinée à^
etre "comparable" codePostal = cp;
population = p;
public interface Comparable<T> { }
public int compareTo(T o);
} public int compareTo(Ville o) {
return population.compareTo(o.population);
Etudiant String Ville }
}
+compareTo(obj: TypeT): int +compareTo(obj: TypeT): int +compareTo(obj: TypeT): int

public class TestComparable {

public static void main(String[] args) {


1. La méthode compareTo() est abstraite et retourne une valeur Ville montpellier = new Ville("Montpellier", 34000, 282143);
Ville sete = new Ville("Sète", 34301, 43620);
entière, censée être :
• positive si l’objet comparable est supérieur à l’objet obj if (montpellier.compareTo(sete) > 0)
System.out.println("Montpellier plus grand");
• 0 (zéro) si l’objet comparable est égal à l’objet obj else if (montpellier.compareTo(sete) < 0)
System.out.println("Sète plus grand");
• négative si l’objet comparable est inférieur à l’objet obj
else System.out.println("ils ont la meme population !");
2. Cette méthode abstraite doit être implémentée dans chaque }
}

réalisation de Comparable .
27 28
Classe cliente d’une interface Héritage : interface
• Quand une classe dépend d’une interface pour réaliser ses En règle générale, une interface est équivalente à une classe
opérations, elle est dite classe cliente de l’interface abstraite qui n’a que des méthodes abstraites et éventuellement des
champs static final .
• On utilise une relation de dépendance entre la classe cliente et
l’interface requise Depuis Java 8 les interfaces peuvent avoir des méthodes par défaut :
«interface» public interface MonInterface {
Voiture ClasseCliente
public void faireQuelqueChose();
+demarrer(): void public class ClasseDeTest {
utilise +traitement(v: Voiture): void
+arreter(): void default public void faireAutreChose(){ public static void main(String[] args) {
System.out.println("Implémentation par défaut"); MonInterface obj = new MaClasse();
} obj.faireQuelqueChose(); // classique
} obj.faireAutreChose(); // default
}
void traitement (Voiture v){ }
Berline Camion ... public class MaClasse implements MonInterface {
v.demarrer() public void faireQuelqueChose(){
+demarrer(): void +demarrer(): void ... System.out.println("Mon implémentation");
+arreter(): void +arreter(): void v.arreter() }
... } Héritage de comportement
}

Code Java
Important
• Toute classe implémentant l’interface pourra être utilisée - Les méthodes par défaut ne peuvent pas manipuler des attributs
principe de substitution dynamiques !
29 30

Transtypage Transtypage et objets


Une classe définit un type, donc le cast est également possible :
Définition - Transtypage public class Animal{ public class Chien extends Animal{ public class Chat extends Animal{
private String nom;
Le transtypage (ou cast en anglais) est un mécanisme de public Animal(String nom){ public Chien(String nom){ public Chat(String nom){
this.nom = nom; super(nom) super(nom)
conversion d’une expression d’un certain type vers un autre type. En } } }

Java il peut être implicite ou explicite. public void dormir(){ public void aboyer(){ public void miauler(){
// du code ici // du code ici // du code ici
} } }
Cast implicite : } } }

int i = 10; Cast implicite :


System.out.println(i); // affiche 10
double d = i; // transtypage implicite de la valeur de i en une valeur de type double Animal animal = new Chien("Doggy"); // upcasting : a est un Animal de sous-type Chien
System.out.println(d); // affiche 10.0 Chien chien = new Chien("Bernny");

Animal[] zoo = new Animal[5]; // un tableau d’objets de type Animal


zoo[0] = animal;
Cast explicite : zoo[1] = chien; // cast implicite

double reel = 13.42;


System.out.println(reel); // affiche 13.42
int entier = (int)reel; // transtypage explicite
Cast explicite :
System.out.println(entier); // affiche 13 Animal a = new Chien ("Bernny");
Chien c = (Chien) a; // cast explicite

En l’utilisant avec attention, parfois le transtypage peut être utile... Voyez-vous un danger avec le cast explicite ?
31 32
Héritage et casting : bêtisier Héritage : bilan
public class Animal{ public class Chien extends Animal{ public class Chat extends Animal{ extends ≈ héritage de type, de comportement et d’état
private String nom;
public Animal(String nom){ public Chien(String nom){ public Chat(String nom){ implements ≈ héritage de type (+ comportement en Java 8)
this.nom = nom; super(nom) super(nom)
} } }
• l’héritage est très pratique et souvent naturel...
public void dormir(){ public void aboyer(){ public void miauler(){
// du code ici // du code ici // du code ici
} } } • ...mais attention au respect du contrat des classes-parentes
} } }

Conseils :
Animal a = new Chien ("Bernny"); // OK ou pas ? • si possible préférez les interfaces plutôt que les classes-mères
Chien c = (Chien) a; // OK ou pas ?
c.aboyer(); //OK ou pas? concrètes −→ alternative plus souple
((Chien)a).aboyer(); //OK ou pas?
Animal b = new Chat ("Tom"); //OK ou pas?
Chien c1 = (Chien) b; //OK ou pas ?
• si votre seul but c’est réutiliser du code, dites-vous bien
c1.aboyer(); //OK ou pas ?

L’opérateur instanceof permet de tester si un objet est d’un type


(ou sous-type) donné.
De manière générale, les architectures bien réfléchies doivent pouvoir
éviter son utilisation... préférez le polymorphisme !
• ... et cherchez une alternative pour le réutiliser
33 34

Vous aimerez peut-être aussi