5. Explication [1]
Les classes Etudiant et Enseignant ont plusieurs similitudes.
Un des avantages de la POO est la possibilité de gérer de telles
similitudes, comme dans une hiérarchie. Cette possibilité s’appelle
héritage.
Quand une classe hérite d’une autre classe, la classe enfant hérite
automatiquement de toutes les caractéristiques (variables membres)
et du comportement (méthodes) de la classe mère. L’héritage est
toujours additif; il n’est pas possible d’hériter d’une classe et de
recevoir moins que ce que possède la classe mère.
En Java, l’héritage est géré avec le mot clé extends. Quand une
classe hérite d’une autre classe, la classe fille étend la classe mère.
2017-2018
6. Prototypes de 3 classes
public class Personne{
. . .
}
public class Etudiant extends Personne{
. . .
}
public class Enseignant extends Personne{
. . .
}
2017-2018
7. Déclarations
On crée la classe Personne pour gérer les similitudes entre les
classes Etudiant et Enseignant.
Ensuite, on supprime les déclarations des éléments communs
lors de la déclaration des sous-classes Etudiant et Enseignant.
2017-2018
9. class Personne {
String nom, prenom;
int age;
// constructeur par défaut
public Personne() {
nom = "Lazraq";
prenom= "Mohammed";
age = 20;
}
//constructeur avec paramètres
public Personne(String nom, String prenom, int age){
this.nom = nom;
this.prenom= prenom;
this.age = age;
} 2017-2018
La classe Personne
10. String getNom(){
return nom;
}
String getPrenom(){
return prenom;
}
int getAge(){
return age;
}
public String toString(){
return getNom()+" "+getPrenom()+" est agé de "+
getAge()+ " ans.";
}
}
2017-2018
11. public class Etudiant extends Personne{
long cne;
public Etudiant() {
super(); // appel du constructeur par défaut de la classe mère
cne= 123654789;
}
public Etudiant(String nom, String prenom, int age, long cne){
// appel du constructeur avec param de la classe mère
super(nom, prenom, age);
this.cne= cne;
}
long getcne(){
return cne;
}
}
La classe Etudiant
2017-2018
12. La méthode toString()
Le polymorphisme est la possibilité pour deux classes séparées, mais
reliées, d’avoir la même méthode mais l’implémenter de façon différente.
Le mot clé super permettra d’accéder à toutes les méthodes ou variables
membre de la classe de niveau supérieur.
Nous ajoutons le code suivant à la classe Etudiant:
public String toString(){
return super.toString()+"C'est un étudiant de cne: " +getcne();
}
2017-2018
13. Appel dans le programme principal
public static void main(String[] args){
Etudiant E1 = new Etudiant("Lotfi","Karim", 22, 1472585);
Etudiant E2 = new Etudiant();
System.out.println(E1.toString());
System.out.println(E2.toString());
}
Résultat:
Lotfi Karim est agé de 22 ans. C'est un étudiant de cne: 1472585
Lazraq Mohammed est agé de 20 ans. C'est un étudiant de cne:
123654789
2017-2018
14. Exemple [http://fr.openclassrooms.com/informatique/cours/apprenez-a-programmer-en-java/l-
heritage-1]
//Définition d'un tableau de villes null
Personne[] tableau = new Personne[6];
//Définition d'un tableau de noms de personnes et un autre de leurs ages
String[] tab1 = {"Lmarss", "Latfi", "Maaroufi", "Yassini", "Allali"};
int[] tab2 = {22, 21, 22, 21, 21,};
//Les trois premiers éléments du tableau seront des personnes, et le reste, leurs ages
for(int i = 0; i < tab1.length; i++){
if (i <3){
Ville V = new Ville(tab[i], tab2[i], "france");
tableau[i] = V;
}
else{
Capitale C = new Capitale(tab[i], tab2[i], "france", "la tour Eiffel");
tableau[i] = C;
}
}
//Il ne nous reste plus qu'à décrire tout notre tableau !
for(Ville V : tableau){
System.out.println(V.decrisToi()+"n");
}
2017-2018
15. Les modificateurs d'accès [1]
A l'intérieur d'une classe, on peut accéder à tous les attributs et les
méthodes directement par leur nom (accès direct).
Tous les attributs et méthodes
sont accessibles directement à
l’intérieur de la classe Personne.
Il suffit d’utiliser le nom de
l’attribut ou celui de la méthode.
Exemple:
nom, getnom(), toString(), etc.
class Personne{
private String nom, prénom;
private int âge;
protected String getnom(){….}
protected String getprénom(){….}
protected int getâge(){….}
String toString(){…}
public static void main(){…}
}
2017-2018
16. Suite
L'accès aux attributs et aux méthodes à l'extérieur des classes Java
dépend des modificateurs d'accès. Ces modificateurs définissent
divers degrés d'accès aux membres des classes.
Les modificateurs d'accès sont indiqués juste avant le type de la
variable ou de résultat pour les méthodes.
Exemples :
public String nom;
protected String prénom;
private int âge;
String toString()
2017-2018
17. Suite
Il existe quatre modificateurs d'accès:
par défaut (il n'y a pas de modificateur): seules les classes de même
paquetage peuvent accéder aux données membres.
public: les membres sont accessibles à tous, que ce soit de
l'intérieur ou de l'extérieur de la classe ou du paquetage:
protected: les membres ne sont accessibles qu'aux méthodes dans
cette classe et dans les classes dérivées de cette classe ou du
paquetage.
private: les membres ne sont accessibles qu'aux méthodes dans la
classe où ils ont été définis (accès direct).
Remarque: En règle générale, il vaut mieux limiter la portée des
éléments des programmes (dont les membres des classes) autant que
possible; moins un élément est accessible, moins il risque d’être mal
utilisé. 2017-2018
18. Niveaux d’accès [1]
Modificateur d’accès Héritage Accessible
Par défaut (pas de modificateur) Oui Oui
public Oui Oui
protected Oui Oui
private Non Non
2017-2018
Accès depuis l’intérieur du paquet d’une classe
Ce tableau montre comment les autres membres du même paquet
accèdent aux membres d’une classe et en héritent.
Par exemple, un membre déclaré private est inaccessible depuis les
autres membres du même paquet et il est impossible d’en hériter.
Les membres déclarés avec les autres modificateurs sont accessibles
depuis les autres membres de ce paquet qui peuvent aussi en hériter.
19. Exemple
2017-2018
Paquet Package1
class Personne{
private String nom, prénom;
private int âge;
protected String getnom(){….}
protected String getprénom(){….}
protected int getâge(){….}
String toString(){…}
public static void main(){…}
}
class Voiture{
…
getnom(), getprénom(), getâge() : protected
toString(): par défaut
main(): public
}
class Etudiant extends Personne{
…
getnom(), getprénom(), getâge() : protected
toString(): par défaut
main(): public
}
20. Niveaux d’accès (Suite)
2017-2018
Modificateur d’accès Héritage Accessible
Par défaut (pas de modificateur) Non Non
public Oui Oui
protected Oui Non
private Non Non
Accès depuis l’extérieur du paquet d’une classe
Ce tableau montre qu’il est possible d’hériter d’un membre de
type protected mais qu’il est impossible d’y accéder à partir de
classes situées en dehors de son paquet.
21. Exemple
2017-2018
Paquet Package1
class Personne{
private String nom, prénom;
private int âge;
protected String getnom(){….}
protected String getprénom(){….}
protected int getâge(){….}
String toString(){…}
public static void main(){…}
}
class Voiture{
…
main(): public
}
class Etudiant extends Personne{
…
getnom(), getprénom(), getâge() : protected
main(): public
}
Paquet Package2
22. L’opérateur instanceof [2]
instanceof permet de savoir la classe à laquelle une instance (un objet) appartient.
B
D
C
Soit le cas de figure suivant:
class B{ …}
class D extends B{…}
class C {…}
B b = new B();
D d = new D();
C c = new C();
Groupe 1 d’instructions:
b instanceof B // true
b instanceof D // false
d instanceof B // true
d instanceof D // true
Groupe 2 d’instructions:
b = d; // si on ajoute b=d
b instanceof B // true
b instanceof D // true
c instanceof B /* erreur de compilation:
Les types C and B sont incompatibles. */
2017-2018
23. Exemple
Vérification des objets qui appartiennent à la classe Personne.
class Personne {
private String nom, prenom;
private int age;
// constructeur par défaut
public Personne() {
nom = "Lazraq";
prenom= "Mohammed";
age = 20;}
//constructeur avec paramètres
public Personne(String nom, String prenom, int age) {
this.nom = nom;
this.prenom= prenom;
this.age = age;}
public String getNom(){ return nom; }
public String getPrenom(){ return prenom; }
public int getAge(){ return age; }
public String toString(){
return getNom()+" "+getPrenom()+" est agé de "+getAge()+ " ans.";
} 2017-2018
24. public static void main(String[] args){
Personne p1=new Personne("Lotfi","Karim", 22);
Personne p2=new Personne("Lotfi","Karim", 22);
System.out.println(p1.toString());
System.out.println(p2.toString());
System.out.println("p2 est une instance de Personne: "+ (p2 instanceof Personne));
System.out.println("p1.equals(p2): "+p1.equals(p2));
}
}
Résultat:
Lotfi Karim est agé de 22 ans.
Lotfi Karim est agé de 22 ans.
p2 est une instance de Personne: true
p1.equals(p2): false
Remarque: L’implémentation par défaut de la méthode equals(Object) est:
public boolean equals(Object obj) {
return (this == obj); // comparaison des identités
}
Pour que p1.equals(p2) donne un résultat true, il faut redéfinir la méthode equals(Object).
2017-2018
25. Redéfinition de equals(Object obj) [3]
La méthode equals(Object obj) qui compare 2 objets utilise dans son code
l’opérateur instanceof.
public boolean equals(Object obj) {
if ( this == obj ) return true; // avoir la même identité
if ( !(obj instanceof Personne)) return false;
Personne p=(Personne)obj; // cast sur obj
return (nom==p.nom && prenom==p.prenom && age==p.age);
}
Après l’ajout de la redéfinition de la méthode equals(Object) à la classe
Personne, on obtient les résultats suivants:
2017-2018
Résultat:
Lotfi Karim est agé de 22 ans.
Lotfi Karim est agé de 22 ans.
p2 est une instance de Personne: true
p1.equals(p2): true
26. Remarques
L’héritage permet:
la généricité du code: un traitement peut être écrit pour manipuler un
objet d’une classe A, et ce même traitement pourra fonctionner sur
tous les objets dont les classes héritent directement ou indirectement
de la classe A. Exemple: getAge() fonctionne avec des objets des
classes Personne et Etudiant.
Le polymorphisme: un objet peut se faire passer comme appartenant à
plusieurs classes (toutes celles de sa branche généalogique), et donc
d’être de plusieurs types simultanément.
Exemple: Etudiant E1=new Etudiant();
E1 appartient à la fois aux classes Etudiant et Personne.
Mais l’utilisation du seul mécanisme de l’héritage produit un code lourd et
parfois peu cohérent quand on essaie d’exploiter ces 2 propriétés.
3 mécanismes viennent donc compléter et enrichir l’héritage: Les classes
abstraites, les interfaces et les types génériques (Chapitre suivant).
2017-2018
27. Suite [2]
Il ne faut pas confondre la redéfinition avec la surcharge :
Redéfinition: même type de retour et mêmes paramètres (exp:
toString()).
Surcharge: type de retour et/ou paramètres différents, les paramètres au
moins doivent être différents (Constructeurs).
Il n’y’a pas d’héritage multiple en Java, càd, une classe ne peut pas dérivée de
plusieurs classes.
Une classe définie avec le modificateur d’accès final ne peut pas être dérivée.
Une méthode définie avec le modificateur d’accès final ne peut pas être
redéfinie dans les classes dérivées. Ceci peut se faire pour des raisons :
d’efficacité : le compilateur peut générer du code inline, sans faire appel à
la méthode.
de sécurité : le mécanisme de polymorphisme dynamique fait qu’on ne
sait pas quelle méthode va être appelée.
2017-2018
29. Présentation [1]
Dans une classe, il est possible de déclarer une méthode comme
étant abstraite, càd que la méthode n’a pas d’implémentation
(code) dans cette classe.
Mais toutes les classes qui dérivent de celle-ci doivent fournir
une implémentation.
Quand une classe contient une méthode abstraite, la totalité de la
classe doit être déclarée comme abstraite. Cela signifie qu’une
classe qui inclut au moins une méthode abstraite (càd une classe
abstraite) ne peut pas être instanciée.
2017-2018
30. Exemple
Supposons que nous voulons manipuler deux formes géométriques:
Rectangle (définie par son point haut, gauche, sa largeur et sa
longueur) et
Cercle (définie par les coordonnées de son centre et son rayon).
Nous désirons calculer leur surfaces. Forme
int x, y
Forme()
Surface()
Cercle
int rayon
Cercle()
Surface()
Rectangle
int larg, long
Rectangle()
Surface()
2017-2018
31. La classe abstraite Forme
abstract class Forme{
int x, y;
Forme(int x, int y){
this.x = x;
this.y = y;
}
abstract double surface();
}
2017-2018
32. La sous classe Rectangle
class Rectangle extends Forme{
int largeur, longueur;
Rectangle(int x, int y, int largeur , int longueur ){
super(x, y);
this.largeur = largeur ;
this.longueur = longueur ;
}
double surface(){
return largeur*longueur;
}
}
2017-2018
33. La sous classe Cercle
class Cercle extends Forme{
int rayon;
Cercle(int x, int y, int r){
super(x, y);
this.rayon = rayon;
}
double surface(){
return Math.PI*rayon*rayon;
}
}
2017-2018
34. Avantages
Les classes abstraites permettent de factoriser du code dans une
classe mère dans laquelle :
certaines méthodes seront génériques : partagées par toutes
les classes filles.
certaines méthodes seront spécifiques : propres à chacune des
classes filles et donc définies (de façon obligatoire) dans
chacune d’elles.
2017-2018