Upload
others
View
4
Download
0
Embed Size (px)
Citation preview
Programmation orientée objet Introduction à JAVA
R. N. GUIBADJ EILCO, ING1
La programmation orientée objet
• Les objectifs : • Faciliter le développement et l’évolution des applications • Permettre le travail en équipe • Augmenter la qualité des logiciels (moins de bugs)
• Solutions proposées : • Découpler (séparer) les parties des projets • Limiter (et localiser) les modifications lors des évolutions • Réutiliser facilement du code.
Le langage Java
• Le langage Java : • est un langage de programmation orienté objet • créé par James Gosling et Patrick Naughton (Sun) • présenté officiellement le 23 mai 1995.
• Les objectifs de Java : • simple, orienté objet et familier • robuste et sûr • indépendant de la machine employée pour l'exécution • très performant • interprété, multitâches et dynamique
Premier exemple
• Dans un fichier de nom HelloWorld.java
• Règle: toute classe publique doit être dans un fichier qui a le même nom que la classe
• Règle: tout code doit être à l'intérieur d'une classe
• Ça définit une classe, qui est une unité de compilation
• Comme il y a une méthode main, cette classe est «exécutable»
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Bonjour à vous!");
}
}
Un langage compilé / interprété
Compilateur
Interpréteur
Système d’exploitation
Code source
Bytecode
Code machine
Javac HelloWorld.java
Java HelloWorld
Système d’exploitation
HelloWorld.java
HelloWorld.class
Virtualisation
Types de données en Java
• 2 grands groupes de types de données :
• types primitifs • objets (instances de classe)
• Java manipule différemment les valeurs des types primitifs et les objets : les variables contiennent
• des valeurs de types primitifs • ou des références aux objets
Types primitifs
• Valeur logique • boolean (true/false)
• Nombres entiers • byte (1 octet), short (2octets), int (4 octets), long (8 octets)
• Nombres non entiers (à virgule flottante) • float (4 octets), double (8 octets).
• Caractère (un seul) • char (2 octets) ; codé par le codage Unicode (et pas ASCII)
Contrôle du flot d’instructions
• Expression du choix : Alternative
• if (condition) • séquence-d-instructions
if (condition) • séquence-d-instructions1 • else
séquence-d-instructions2
Contrôle du flot d’instructions
• Expression du choix : Aiguillage
Switch (expression_discrète) { case valeur_1 : séquence-d-instructions break; case valeur_2 : séquence-d-instructions break; …. case valeur_n : séquence-d-instructions break; default : séquence-d-instructions }
Contrôle du flot d’instructions
La boucle while : • while (condition_itération) { instructions;}
La boucle do … while : do { instructions; } while (condition_itération); • • La boucle for : • for (initialisation ; condition-continuation ; variation-compteur) {
instructions ;} •
Entrées/sorties sur console
• Affichage sur la console • System.out.print(chaîne de caractères à afficher) • System.out.println(chaîne de caractères à afficher)
• chaîne de caractères peut être : • une constante chaîne de caractères (String)
System.out.println("coucou"); • une expression de type String
System.out.println(age); • une combinaison (concaténation) de constantes et d'expressions de type
String. La concaténation est exprimée à l'aide de l'opérateur +
System.out.println("L'age de la personne est " + age + " son poids " + poids);
Tableaux unidimensionnels
• Déclaration • typeDesElements[] nomDuTableau;
• typeDesElements un des types de base du langage JAVA (char, int, float, double...) ou un nom de classe
• nomDuTableau l’identificateur pour désigner le tableau • • Exemples
int[] vecteurEntiers; Compte[] listeDesComptes;
Tableaux unidimensionnels
• typeDesElements[] nomDuTableau; définit (déclare) un identificateur nomDuTableau qui permettra de
désigner (référencer) un tableau du type déclaré ("tableau d'éléments de type typeDesElements"). • mais ne crée pas de tableau en mémoire. (nomDuTableau == null)
• Pour utiliser un tableau, après la déclaration d’un identificateur permettant de le désigner, il faut ensuite explicitement "créer" ce tableau en mémoire. • la "création" s’effectue à l’aide de l’opérateur new • nomDuTableau = new typeDesElements[taille]
Tableaux unidimensionnels
• La création d’un tableau par new
• alloue la mémoire nécessaire en fonction
• du type du tableau
• de la taille spécifiée mais ne crée pas de tableau en mémoire. • initialise le contenu du tableau
• type simple : 0
• type complexe (classe) : null
• Exemple
int[] t1; t1 = new int[7]; int[] t2 = t1;
Tableaux unidimensionnels
• accès à un élément d'un tableau s'effectue à l'aide d'une expression de la forme :
nomDuTableau[expression1] • expression1 est une expression entière qui définit l’index dans le
tableau de l’élément considéré
• comme en C/C++ les éléments d’un tableau sont indexés de 0 à taille-1
• Java vérifie automatiquement l'indice lors de l'accès (comparaison avec la borne) • Si hors limites : ArrayIndexOutOfBoundsException
• Evite des bugs !
Tableaux unidimensionnels
• nomDuTableau.length donne la taille du tableau nomDuTableau int[] tabEntiers = new int[10] tabEntiers.length 10 taille du tableau
tabEntiers.length -1 indice max de tabEntiers
• L’argument String[] args du main est un tableau de chaînes de caractères (String) correspondant aux arguments de la ligne de commande.
public class Test{ public static void main(String[] args) {System.out.println("nombre d ’arguments : " + args.length); for (int i =0; i < args.length; i++) System.out.println(" argument " + i + " = " + args[i]); }}
Tableaux unidimensionnels
• Une autre manière de créer des tableaux : • en donnant explicitement la liste de ses éléments à la déclaration
(liste de valeurs entre accolades) • exemples :
int[] t1 = { 1, 2 ,3, 4, 5}; char[] codes = { 'A', 'a', 'B', 'z' }; • l ’allocation mémoire (équivalent de l’utilisation de new) est prise en
charge par le compilateur
Tableaux multidimensionnels
• tableau dont les éléments sont eux mêmes des tableaux • un tableau à deux dimensions se déclarera ainsi de la manière
suivante : typeDesElements[][] nomduTableau; • exemples
• double[][] matrice; • Voxel[][][] cubeVoxels;
Tableaux multidimensionnels
• Les dimensions du tableau ne sont pas spécifiées à la déclaration (comme pour les tableaux à une seule dimension).
• Les dimensions sont indiquées que lors de la création
• obligatoire que pour la première dimension. • autres dimensions peuvent n'être spécifiées que lors de la création
effective des tableaux correspondants. • Exemple
double [][] matrice = new double[4][4]; double [][] matrice = new double[4][]; for (int i=0; i < 4; i++) matrice[i] = new double[4]; double [][] matrice; matrice = new double[4][]; for (int i=0; i < 4; i++) matrice[i] = new double[4];
Programmation orientée objet Classes et Objets
R. N. GUIBADJ EILCO, ING1
Classe
• Une classe est constituée de descriptions de : • données : que l’on nomme attributs. • procédures : que l’on nomme méthodes
• Une classe est un modèle de définition pour des objets • ayant même structure (même ensemble d'attributs), • ayant même comportement (mêmes opérations, méthodes), • ayant une sémantique commune.
• Les objets sont des représentations dynamiques (instanciation), « vivantes » du modèle défini pour eux au travers de la classe. • Une classe permet d’instancier (créer) plusieurs objets • Chaque objet est instance d’une (seule) classe
Classe : Notation UML
Point
x : double
y : double
translater(x : double ,y : double) distance() : double
...
Nom de la classe
attributs
méthodes
Classe : Syntaxe JAVA
class Point {
double x; double y;
void translater(double dx, double dy) {x += dx; y += dy;}
double distance() {double dist; dist = Math.sqrt(x*x+y*y); return dist;}
}
fichier Point.java
!!! Le nom doit être identique au nom de la classe
Objets
• Un objet est instance d'une (seule) classe : • il se conforme à la description que celle-ci fournit, • il admet une valeur (qui lui est propre) pour chaque attribut
déclaré dans la classe
• ces valeurs caractérisent l’état de l ’objet • il est possible de lui appliquer toute opération (méthode) définie
dans la classe
• Tout objet admet une identité qui le distingue pleinement des autres objets : • il peut être nommé et être référencé par un nom
Objets : notation uml
Point
x : double
y : double
translater(x : double ,y : double) distance() : double
point1 : Point
x =22
Y=14
Notation d'un objet point1, instance de la classe Point
«instance of»
Création d’Objets
• La création d ’un objet à partir d’une classe est appelée instanciation. L’objet créé est une instance de la classe.
• Instanciation se décompose en trois phases : 1) obtention de l ’espace mémoire nécessaire à la partie dynamique
de l’objet et initialisation des attributs en mémoire (à l’image d’une structure)
2) appel de méthodes particulières, les constructeurs, définies dans la classe.
3) renvoi d’une référence sur l’objet (son identité) maintenant créé et initialisé.
Création d’Objets
• new constructeur (liste de paramètres) • les constructeurs ont le même nom que la classe • il existe un constructeur par défaut
• sans paramètres • réduit à phase 1 (allocation mémoire) • inexistant si un autre constructeur existe
Point p1; p1 = new Point(); Point p2 = new Point(); Point p3 = p2;
L’objet courant : mot clé « this »
• Par convention, l’objet courant est désigné par this • c’est une référence particulière
• désigne l’objet courant (objet récepteur du message, auquel s’appliquent les instructions du corps de la méthode où this est utilisé)
• peut être utilisé pour rendre explicite l'accès aux propres attributs et méthodes définies dans la classe
• this.x ou x désignent le même attribut de l’objet courant
Encapsulation
• accès direct aux variables d'un objet possible en JAVA • mais ... n'est pas recommandé car contraire au principe d'encapsulation
• les données d'un objet doivent être privées (c'est à dire protégées et accessibles (et surtout modifiables) qu'au travers de méthodes prévues à cet effet).
• en JAVA, possible lors de leur définition d'agir sur la visibilité (accessibilité) des membres (attributs et méthodes) d’une classe vis à vis des autres classes
• plusieurs niveaux de visibilité peuvent être définis en précédant d'un modificateur (private, public, protected,) la déclaration de chaque attribut, méthode ou constructeur
Notes sur les constructeurs
• Les constructeurs sont des méthodes particulières qui ne sont appelées que lors de la création de l’objet.
• Un constructeur n’a pas de type de retour, même pas un void
• Le(s) constructeurs sont en général de type public
• Les méthodes de types constructeurs ne sont jamais appelées directement. Elles sont appelées par l’intermédiaire du mot clef new.
• A l’intérieur de la classe, un constructeur peut appeler un autre constructeur en utilisant le mot clef this
Attributs d’instances
• Dans la classe Point, les variables x et y sont des variables d’instances • Cela signifie que les attributs x et y sont créés pour chaque objet de
type Point • Si on crée 10 objets de type Point, on crée 10 couples de variables x et
y ( qui auront à priori des valeurs différentes)
Attributs de classe
• Les attributs de classes sont associés à la classe et non individuellement aux objets de la classe
• On utilise le mot clef static devant un attribut pour indiquer qu’il est partagé par tous les objets de la classe
• Quelques exemples d’attributs statiques • Nombre d’objets créé par la classe
• Constantes (taille max et min d’un Rectangle) • Variables globales utilisées par les objets
Méthode d’instance/ Méthode de classe
• Comme pour les attributs, il est possible d’avoir des méthodes d’instance ou de classe
• Un méthode de classe est appelée sur la classe et non pas sur les objets
• Elle est introduite comme pour les attributs par le mot clef static. Pour l’appeler, on appelle le nom de la classe suivi du nom de la méthode.
• Exemple : • Math.abs() est une méthode de classe calculant la valeur absolue
d’un nombre
Programmation orientée objet réutilisation des classes
délégation, héritage
R. N. GUIBADJ EILCO, ING1
Réutilisation : introduction
• Comment utiliser une classe comme brique de base pour concevoir d’autres classes ?
• Dans une conception objet on définit des associations (relations) entre classes pour exprimer la réutilisation.
• UML (Unified Modelling Language http://uml.free.fr) définit toute une typologie des associations possibles entre classes. Dans cette introduction, nous nous focaliserons sur deux formes d’association • Un objet peut faire appel à un autre objet : délégation • Un objet peut être créé à partir du « moule » d’un autre objet :
héritage
Délégation
• Un objet o1 instance de la classe C1 utilise les services d’un objet o2 instance de la classe C2
• La classe C1 utilise les services de la classe C2 • C1 est la classe cliente • C2 est la classe serveuse
• Notation UML
• Syntaxe Java
• La classe cliente (C1) possède une référence de type de la classe
serveuse (C2)
Public class C1{
…
}
Public class C2{
...
}
C1 C2
private C2 refC2;
refC2
Délégation : exemple
• Exemple la classe Cercle • rayon : un double
• centre : deux doubles (x et y) ou bien Point • L’association entre les classes Cercle et Point exprime le fait qu’un cercle
possède un centre
Cercle Point centre
1
Délégation : exemple 1
public class Cercle { private Point centre; //centre du cercle
private double r; // rayon du cercle
public Cercle( Point centre, double r) { this.centre = centre; this.r = r; } …
public void translater(double dx, double dy) { centre.translater(dx,dy); } …
}
Délégation : exemple 1
• Le point représentant le centre a une existence autonome (cycles de vie indépendants)
• Il peut être partagé (à un même moment il peut être lié à plusieurs instances d'objets ) .
• Il peut être utilisé en dehors du cercle dont il est le centre (Attention aux
effets de bord)
c1 : Cercle
centre r = 10
c2 : Cercle
centre r = 20
p1 : Point
y = 30
y = 5
Point p1 = new Point(10,0); Cercle c1 = new Cercle(p1,10); Cercle c2 = new Cercle(p1,20); c2.translater(10,0); // affecte aussi le cercle c1
p1. translater(10,5); // affecte les deux cercles c1 et c2
Délégation : exemple 2
public class Cercle {
private Point centre; //centre du cercle
private double r; // rayon du cercle
public Cercle( Point centre, double r) { this.centre = new Point(centre); this.r = r; } …
public void translater(double dx, double dy) { centre.translater(dx,dy); } …
}
Délégation : exemple 2
• Le Point représentant le centre n’est pas partagé (à un même moment, une instance de Point ne peut être liée qu'à un seul Cercle)
• les cycles de vies du Point et du Cercle sont liés : si le cercle est détruit (ou
copié), le centre l’est aussi.
Point p1 = new Point(10,0); Cercle c1 = new Cercle(p1,10) Cercle c2 = new Cercle(p1,20); c2.translater(10,0); // n'affecte que le cercle c2
p1. translater(10,5); // n'affecte pas les cercles c1 et c2
c1 : Cercle
centre r = 10
c2 : Cercle
centre r = 20
p1 : Point
y = 10
y = 5
p1 : Point
y = 20
y = 0
p1 : Point
y = 10
y = 0
Agrégation / Composition
• Les deux exemples précédents traduisent deux nuances (sémantiques) de l’association a-un entre la classe Cercle et la classe Point
• UML distingue ces deux sémantiques en définissant deux type de relations :
Voiture
Roue
0 .. 4
Agrégation
Cercle
Point
1
Composition
L’élément agrégé (Roue) a une existence autonome
en dehors de l’agrégat (Voiture)
Agrégation forte
A un même moment, une instance de composant (Point) ne peut être liée qu'à un seul agrégat (Cercle), et le composant a un cycle de vie
dépendant de l’agrégat.
Héritage : Exemple introductif
• Le problème • une application a besoin de services dont une partie seulement est
proposée par une classe déjà définie (classe dont on ne possède pas nécessairement le code source)
• ne pas réécrire le code • Exemple
• L’application a besoin de manipuler des points (comme le permet la classe Point) mais en plus les dessiner sur l’écran.
• PointGraphique = Point + une couleur + une opération d’affichage • Solution en POO : l’héritage (inheritence)
• définir une nouvelle classe à partir de la classe déjà existante
Héritage : syntaxe java
• La classe PointGraphique hérite de la classe Point
import java.awt.Colors; import java.awt.Graphics; public class PointGraphique extends Point { Color coul; // constructeur public PointGraphique(double x, double y,Color c) { this.x = x; this.y = y; this.coul = c; } // affiche le point matérialisé par un rectangle de 3 pixels de coté
public void dessine(Graphics g) { g.setColor(coul); g.fillRect((int) x - 1,(int)y - 1,3,3); } }
• PointGraphique hérite de (étend) Point
• un PointGraphique possède les variables et méthodes définies dans la classe Point
PointGraphique définit un nouvel attribut
Attributs hérités de la classe Point
PointGraphique définit une nouvelle méthode
Héritage : utilisation des instances d’une classe héritée
• Un objet instance de PointGraphique possède les attributs définis dans PointGraphique ainsi que les attributs définis dans Point (un PointGraphique est aussi un Point )
• Un objet instance de PointGraphique répond aux messages définis par les méthodes décrites dans la classe PointGraphique et aussi à ceux définis par les méthodes de la classe Point
PointGraphique p = new PointGraphique(); // utilisation des variables d’instance héritées p.x = 15; p.y = 11; // utilisation d’une variable d’instance spécifique
p.coul = new Color(255,0,0); // utilisation d’une méthode héritée
double dist = p.distance(); // utilisation d’une méthode spécifique
p.dessine(graphicContext);
x 15
y 11
coul
r 255
v 0
0 b
p
Héritage : terminologie
• Héritage permet de reprendre les caractéristiques d’une classe M existante pour les étendre et définir ainsi une nouvelle classe F qui hérite de M.
• Les objets de F possèdent toutes les caractéristiques de M avec en plus celles définies dans F • Point est la classe mère et PointGraphique est la classe fille. • la classe PointGraphique hérite de la classe Point • la classe PointGraphique est une sous-classe de la classe Point • la classe Point est la super-classe de la classe PointGraphique
• la relation d'héritage peut être vue comme une relation de
“généralisation/spécialisation” entre une classe (la super-classe) et plusieurs classes plus spécialisées (ses sous-classes).
Héritage : Généralisation/Spécialisation
• La généralisation exprime une relation “est-un” entre une classe et sa superclasse (chaque instance de la classe est aussi décrite de façon plus générale par la super-classe).
• La spécialisation exprime une relation de “particularisation” entre une
classe et sa sous-classe (chaque instance de la sous-classe est décrite de manière plus spécifique)
Animal
Éléphant
spécialisation généralisation
Animal est une généralisation
d’Éléphant. Un éléphant est un animal
Éléphant est une spécialisation d’Animal. Un éléphant est un cas
particulier animal
Super classe
Sous classe
Héritage : Généralisation/Spécialisation
• Utilisation de l’héritage : • dans le sens “spécialisation” pour réutiliser par modification
incrémentielle les descriptions existantes • dans le sens “généralisation” pour abstraire en factorisant les propriétés
communes aux sous-classes
Point
Point Graphique
Animal
Elephant Tortue Cheval
Héritage
• pas de limitation dans le nombre de niveaux dans la hiérarchie d'héritage • méthodes et variables sont héritées au travers de tous les niveaux
Equipement
nom
fabriquant Poids coût
Pompe
pression
débit
Echangeur
superficie
diamètre
longueur
Citerne
volume
pression
Piston
taille
PompeCentrifuge
nbrePales axe
CiterneSpherique
diamètre
… …
Héritage : Redéfinition des méthodes
• une sous-classe peut ajouter des variables et/ou des méthodes à celles qu'elle hérite de sa super-classe.
• une sous-classe peut redéfinir (override) les méthodes dont elle hérite et fournir ainsi des implémentations spécialisées pour celles-ci
• Redéfinition d’une méthode (method overriding)
• lorsque la classe définit une méthode dont le nom, le type de retour et le type des arguments sont identiques à ceux d’une méthode dont elle hérite
• Lorsqu’une méthode redéfinie par une classe est invoquée pour un objet de
cette classe, c’est la nouvelle définition et non pas celle de la super-classe qui est invoquée.
Héritage : Redéfinition des méthodes
public class A { public void hello() { System.out.println(«Hello»); } public void affiche() { System.out.println(«Je suis un A»); } }
public class B extends A { public void affiche() { System.out.println(«Je suis un B»); } }
A a = new A();
B b = new B();
a.hello(); --> Hello
a.affiche(); -->Je suis un A
b.hello(); --> Hello
b.affiche(); -->Je suis un B
Héritage : Redéfinition des méthodes
• Ne pas confondre redéfinition (overriding) avec surcharge (overloading)
public class A { public void methodX(int i) { ... } }
public class B extends A { public void methodX(Color i) { ... } }
public class B extends A { public void methodX(int i) { ... } }
B possède deux
méthodes methodX
(methodX(int) et methodX(Color))
C possède une seule
méthode methodX (methodX(int))
Surcharge Redéfinition
Héritage : Redéfinition des méthodes
• Lors d'une redéfinition utiliser l'annotation @Override • Evite de faire une surcharge alors que l'on veut faire une redéfinition
public class A {
protected double x;
public void add (double x)
{
System.out.println("A.add double"+x);
this.x +=x;
}
}
public class B extends A {
public void add (int x)
{
System.out.println("C.add int"+x);
this.x +=x;
}
}
public class C extends A {
@Override
public void add (double x)
{
System.out.println("C.add int"+x);
this.x +=x;
}
}
Héritage : Redéfinition des méthodes
• Redéfinition d’une méthode (method overriding) • lorsque la classe définit une méthode dont le nom, le type de retour et
le type des arguments sont identiques à ceux d’une méthode dont elle hérite
• avant Java 5 : le type de retour doit être le même • Java 5 et + : le type du résultat peut être une sous-classe
public class A { … }
public class B extends A { … }
public class C1 { public A uneMethode() { … } }
public class C2 extends C1 { public B uneMethode() { … } }
Le type du résultat de uneMethode est A
Le type du résultat de uneMethode est B B est une sous classe de A A uneMethode()de C1 est rédéfinie dans C2 comme B uneMethode()
Héritage : Redéfinition des méthodes
• Redéfinition des méthodes (method overriding) : • possibilité de réutiliser le code de la méthode héritée (super)
public class Etudiant {
String nom; String prénom; int age; ... public void affiche() { System.out.println("Nom : " + nom + " Prénom : " + prénom); System.out.println("Age : " + age); ... } ... }
public class EtudiantSportif extends Etudiant { String sportPratiqué; ... public void affiche() { super.affiche(); System.out.println("Sport pratiqué : "+sportPratiqué); ... } }
Héritage : particularités de l’héritage en Java
• Héritage simple • une classe ne peut hériter que d’une seule autre classe
• dans certains autres langages (ex C++) possibilité d’héritage multiple • La hiérarchie d’héritage est un arbre dont la racine est la classe Object
(java.lang) • toute classe autre que Object possède une super-classe • toute classe hérite directement ou indirectement de la classe Object • par défaut une classe qui ne définit pas de clause extends hérite de la
classe Object
public class Point extends Object { int x; // abscisse du point int y; // ordonnée du point ... }
Héritage : La classe Object
• Principales méthodes de la classe Object • public final Class getClass()
Renvoie la référence de l’objet Java représentant la classe de l’objet • public boolean equals(Object obj)
Teste l’égalité de l’objet avec l’objet passé en paramètre • protected Object clone()
Crée une copie de l’objet • public int hashCode()
Renvoie une clé de hashcode pour adressage dispersé • public String toString()
Renvoie une chaîne représentant la valeur de l’objet return getClass().getName() + "@" + Integer.toHexString(hashCode());
Héritage : A propos de toString
• du fait que la méthode toString est définie dans la classe Object , on est sûr que quel que soit le type (la classe) de l’objet il saura répondre au message toString()
public class Object { ... }
public class Point { private double x; private double y; ... }
La classe Point ne redéfinit pas toString
Point@2a340e
La classe Point redéfinit toString
Point:[15.0,11.0]
public String toString(){ return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
public String toString(){ return "Point:[" + x +
"," + y + "]"); }
Point p = new Point(15,11); System.out.println(p);
Constructeurs : Réutilisation des constructeurs
• Redéfinition des méthodes (method overriding) : • possibilité de réutiliser le code de la méthode héritée (super)
• De la même manière il est important de pouvoir réutiliser le code des constructeurs de la super classe dans la définition des constructeurs d'une nouvelle classe
• invocation d'un constructeur de la super classe : super(paramètres du constructeur) • utilisation de super(…) analogue à celle de this(…)
Constructeurs : Réutilisation des constructeurs
public class Point { double x,y; public Point(double x, double y) { this.x = x; this.y = y; } ... }
public class PointCouleur extends Point { Color c; public PointCouleur(double x, double y, Color c) { super(x,y); this.c = c; } ... }
Appel du constructeur de la super-classe. Cet appel s’il est présent doit toujours être
la première instruction du corps du constructeur
Constructeurs : Chaînage des constructeurs
• L’appel à un constructeur de la super classe doit toujours être la première instruction dans le corps du constructeur • si la première instruction d'un constructeur n'est pas un appel explicite
à l’un des constructeur de la superclasse, alors JAVA insère implicitement l'appel super()
• chaque fois qu'un objet est créé les constructeurs sont invoqués en remontant en séquence de classe en classe dans la hiérarchie jusqu'à la classe Object
• c'est le corps du constructeur de la classe Object qui est toujours exécuté en premier, suivi du corps des constructeurs des différentes classes en redescendant dans la hiérarchie.
• garantit qu'un constructeur d'une classe est toujours appelé lorsqu'une instance de l'une de ses sous classes est créée • un objet c instance de C sous classe de B elle même sous classe de A est
un objet de classe C mais est aussi un objet de classe B et de classe A. Lorsqu’il est créé, c doit l’être avec les caractéristiques d ’un objet de A de B et de C
Constructeurs : Chaînage des constructeurs
public class Object { public Object() {...} ... }
public class Point extends Object { double x,y; public Point(double x, double y) { super(); // appel implicite
this.x = x; this.y = y; } ... }
public class PointCouleur extends Point { Color c; public PointCouleur(double x, double y, Color c) { super(x,y); this.c = c; } ... }
1
2
3
Ord
re d
es a
pp
els
Ord
re d’exécu
tion
new PointCouleur(…);
Héritage : redéfinition des attributs
• Lorsqu'une sous classe définit une variable d'instance dont le nom est identique à l'une des variables dont elle hérite, la nouvelle définition masque la définition héritée • l'accès à la variable héritée se fait au travers de super
public class ClasseA { int x; }
public class ClasseB extends Classe A { double x; }
public class ClasseC extends Classe B { char x; }
Héritage : Visibilité des variables et méthodes
• principe d'encapsulation : les données propres à un objet ne sont accessibles qu'au travers des méthodes de cet objet • sécurité des données : elles ne sont accessibles qu'au travers de
méthodes en lesquelles on peut avoir confiance • masquer l'implémentation : l'implémentation d'une classe peut être
modifiée sans remettre en cause le code utilisant celle-ci • en JAVA possibilité de contrôler l'accessibilité (visibilité) des membres
(variables et méthodes) d'une classe • public accessible à toute autre classe • private n'est accessible qu'à l'intérieur de la classe où il est défini • protected est accessible dans la classe où il est défini, dans toutes ses
sous-classes et dans toutes les classes du même package • package (visibilité par défaut) n'est accessible que dans les classes du
même package que celui de la classe où il est défini
Héritage : Visibilité des variables et méthodes
private - (package)
protected public
La classe elle même oui oui oui oui
Classes du même
package
non oui oui oui
Sous-classes d'un
autre package
non non oui oui
Classes (non sous-classes) d'un autre package
non non non oui
Héritage : Syntaxe java import java.awt.Color; import java.awt.Graphics;
public class PointGraphique extends Point{ Color coul; // constructeur public void PointGraphique(double x, double y,Color c) { super(x,y); this.coul = c; } // affiche le point matérialisé par // un rectangle de 3 pixels de coté
public void dessine(Graphics g) { g.setColor(coul); g.fillRect((int) x - 1,(int)y - 1,3,3); } }
public class Point { private double x; private double y; ... public double getX() { return x; } ... }
Attributs hérités de la classe Point
Les attributs sont privés dans la super-classe on ne
peut les utiliser directement dans le code de la sous-classe getx() gety()
Héritage : Syntaxe java import java.awt.Color; import java.awt.Graphics;
public class PointGraphique extends Point{ Color coul; // constructeur public void PointGraphique(double x, double y,Color c) { super(x,y); this.coul = c; } // affiche le point matérialisé par // un rectangle de 3 pixels de coté
public void dessine(Graphics g) { g.setColor(coul); g.fillRect((int) x - 1,(int)y - 1,3,3); } }
public class Point { protected double x; protected double y; ... public double getX() { return x; } ... }
Attributs hérités de la classe Point
Les attributs sont protégés dans la super-classe on peut les utiliser directement dans
le code de la sous-classe
Héritage : Visibilité des variables et méthodes
package monPackage; public class Classe2 { Classe1 o1; }
package monPackage; public class Classe3
extends Classe1 { }
package monPackage; public class Classe1 { Private int a ; Int b; Protected int c; Public int d; }
Package monPackage
package tonPackage; public class Classe4 { Classe1 o1; }
package tonPackage; public class Classe5
extends Classe1 { }
Package tonPackage
Les mêmes règles de visibilité s’appliquent aux méthodes
Héritage : Visibilité des classes
• Deux niveaux de visibilité pour les classes : • public : la classe peut être utilisée par n’importe quelle autre classe • package : la classe ne peut être utilisée que par les classes appartenant
au même package
package A; public class ClasseA { ClasseB b; }
package A; class ClasseB
extends ClasseA { }
package B; public class ClasseC { ClasseA a;
ClasseB b; }
Package A Package B
Héritage : Visibilité des classes
• Jusqu’à présent on a toujours dit : • une classe par fichier • le nom du fichier source : le nom de la classe avec extension .java
• En fait la vraie règle est : • une classe publique par fichier • le nom du fichier source : le nom de la classe publique
public class A { ... }
A.java A.class
javac
package x; public class B { ... } class C { ... } class D { ... }
B.class
C.class
C.class
D.class
javac
Héritage : Méthodes finales
• Méthodes finales public final void méthodeX(….) { …. } • « verrouiller » la méthode pour interdire toute éventuelle redéfinition dans
les sous-classes • efficacité
• quand le compilateur rencontre un appel à une méthode finale il peut remplacer l’appel habituel de méthode (empiler les arguments sur la pile, saut vers le code de la méthode, retour au code appelant, dépilement des arguments, récupération de la valeur de retour) par une copie du code du corps de la méthode (inline call).
• si le corps de la méthode est trop gros, le compilateur est censé ne pas faire cette optimisation qui serait contrebalancée par l ’augmentation importante de la taille du code.
• Mieux vaut ne pas trop se reposer sur le compilateur : • utiliser final que lorsque le code n'est pas trop gros ou lorsque l’on
veut explicitement éviter toute redéfinition • méthodes private sont implicitement final (elles ne peuvent être redéfinies)
Héritage : Méthodes finales
• Une classe peut être définie comme finale
• public final class UneClasse {…} • interdit tout héritage pour cette classe qui ne pourra être sous-classée • toutes les méthodes à l’intérieur de la classe seront implicitement
finales (elles ne peuvent être redéfinies) • exemple : la classe String est finale
• Attention à l’usage de final, prendre garde de ne pas privilégier une
supposée efficacité au détriment des éventuelles possibilités de réutiliser la classe par héritage
Programmation orientée objet Héritage et Polymorphisme
R. N. GUIBADJ EILCO, ING1
Surclassement
• tout objet instance de la classe B peut être aussi vu comme une instance de la classe A.
• à une référence déclarée de type A il est possible d'affecter une valeur qui est une référence vers un objet de type B (surclassement ou upcasting).
Etudiant
Etudiant Sportif
Etudiant e; e = new EtudiantSportif(...);
Surclassement
• plus généralement à une référence d'un type donné, il est possible d'affecter une valeur qui correspond à une référence vers un objet dont le type effectif est n'importe quelle sous classe directe ou indirecte du type de la référence
C c; c = new D(); c = new E(); c = new F(); c = new A(); c = new B();
A
B C
D E
F
Surclassement
• Lorsqu'un objet est "sur-classé" il est vu par le compilateur comme un objet du type de la référence utilisée pour le désigner. Ses fonctionnalités sont alors restreintes à celles proposées par la classe du type de la référence
EtudiantSportif es; es = new EtudiantSportif("DUPONT","Jean",25,"Badminton");
Etudiant e; e = es; // upcasting
e.nbInscriptions(); es.nbInscriptions(); es.bonusSportif(); e.bonusSportif();
Etudiant
String nom
String prénom
int age
public Etudiant(String n, String p,int a ) public void affiche() public int nbInscriptions()
Etudiant Sportif
String sportPratiqué
public EtudiantSportif (String n, String p,int a, String s) public void affiche() public double bonusSportif()
Surclassement
• Lorsqu'une méthode d'un objet est accédée au travers d'une référence "surclassée", c'est la méthode telle qu'elle est définie au niveau de la classe effective de l'objet qui est en fait invoquée et exécutée
Etudiant e = new EtudiantSportif( "DUPONT","Jean",25,"Badminton"); e.affiche();
Etudiant
public void affiche() {System.out.println( "Nom : "+nom+"\n" "Prénom : "+prénom+"\n" "Age : "+age+ ...); }
Etudiant Sportif
public void affiche() {super.affiche(); System.out.println( "Sport" : "+sport+"\n" + ...);}
Nom : DUPONT
Prénom : Jean
Age : 25
Sport : Badminton
Polymorphisme
• Le terme polymorphisme décrit la caractéristique d'un élément qui peut se présenter sous différentes formes.
• En programmation Objet, on appelle polymorphisme • le fait qu’un objet d’une classe puisse être manipulé comme s’il
appartenait à une autre classe. • le fait que la même opération puisse se comporter différemment
sur différentes classes de la hiérarchie. • "Le polymorphisme constitue la troisième caractéristique essentielle
d'un langage orienté objet après l'abstraction des données (encapsulation) et l'héritage" Bruce Eckel "Thinking in JAVA"
Polymorphisme
• En utilisant le polymorphisme en association à la liaison dynamique • plus besoin de distinguer différents cas en fonction de la classe
des objets • Il est possible de définir de nouvelles fonctionnalités en héritant
de nouveaux types de données à partir d'une classe de base commune sans avoir besoin de modifier le code qui manipule l'interface de la classe de base
• Développement plus rapide • Plus grande simplicité et meilleure organisation du code • Programmes plus facilement extensibles • Maintenance du code plus aisée
Polymorphisme
ClasseD ClasseF
ClasseB
ClasseA
méthodeX()
ClasseC
méthodeX()
ClasseE
méthodeX()
ClasseA objA; objA = new ClasseE(); objA.methodeX();
la référence peut désigner des objets de classe différente (n’importe quelle sous classe de ClasseA)
Le comportement est différent selon la classe effective de l’objet
Polymorphisme Etudiant
public void affiche() {System.out.println( "Nom : "+nom+"\n" "Prénom : "+prénom+"\n" "Age : "+age+ ...); }
Etudiant Sportif
public void affiche() {super.affiche(); System.out.println( "Sport" : "+sport+"\n" + ...);}
Etudiant Apprenti
public void affiche() {super.affiche(); System.out.println( « Entreprise" : "+entreprise+"\n" + ...);}
GroupeTD td1 = new GroupeTD(); td1.ajouter(new Etudiant("DUPONT", …)); td1.ajouter(new EtudiantSportif("BIDULE","Louis", … , "ski alpin");
Si un nouveau type d’étudiant est défini, le code de GroupeTD
reste inchangé
public class GroupeTD{ Etudiant[] liste = new Etudiant[30]; int nbEtudiants = 0; ... public void ajouter(Etudiant e) { if (nbEtudiants < liste.lenght) liste[nbEtudiants++] = e; } public void afficherListe() { for (int i=0;i<nbEtudiants; i++) liste[i].affiche(); } }
Surcharge et polymorphisme
ClasseA refA = new ClasseA(); ClasseC.methodX(refA); ClasseB refB = new ClasseB(); ClasseC.methodX(refB); refA = refB; // upCasting
ClasseC.methodX(refA);
public class ClasseC { public static void methodeX(ClasseA a){ System.out.println("param typeA"); } public static void methodeX(ClasseB b){ System.out.println("param typeB"); } }
Le choix de la méthode à exécuter est effectué à la compilation en fonction des types déclarés
ClasseA
ClasseB
param TypeA
param TypeB
param TypeA