Les constructeurs
1. CONSTRUCTION DES OBJETS
1.1. Introduction
Un objet n'est généralement pas prêt à être
utilisé après sa création. Il faut donc faire appel à une procédure
d'initialisation qui alimente tout ou partie de ses données
membres. Cet appel risque d'être oublié. Les constructeurs
apportent une solution à ce problème.
Les
constructeurs seront uniquement étudiés en Java ; en pseudo-code,
on pourra continuer d'utiliser une procédure
d'initialisation.
1.2. Notion de constructeur
Il est possible
de déclarer une procédure particulière chargée de l'initialisation
des instances de la classe : le constructeur. Cette procédure
membre porte le nom de sa classe.
A partir du
moment où un constructeur est défini pour une classe, aucun objet
de cette classe ne peut être créé sans appel à l'un des
constructeurs définis alors que si l'on ne définit aucun
constructeur (c'est ainsi que nous avons procédé jusqu'à
maintenant), Java crée l'objet avec un constructeur implicite qui
ne contient bien sûr aucune instruction ; dans ce cas, les données
de l'objet sont initialisées à 0 si elles sont numériques, à False
s’il s’agit de booléens et non initialisées s'il s'agit d'un
caractère (donc le caractère sera à null qui est le code Unicode
\u0000) ou d'une chaîne (donc la chaîne vaudra null).
Un constructeur
permet d'initialiser certains champs d'un objet dès sa création, ce
qui permet de garantir la cohérence d'un objet. En effet, même si
vous précisez aux utilisateurs d'une classe qu'ils doivent
alimenter tel ou tel champ d'un nouvel objet avant d'effectuer
certaines opérations sur celui-ci, rien ne garantit qu'ils le
feront effectivement, ce qui peut être source de bugs.
C'est le new
Nomclasse (liste éventuelle de paramètres) qui provoque
l'appel au constructeur.
Exemple
:
Déclaration de la classe Date2 et
définition du constructeur
public class Date2
{
private int
jj, mm, aaaa;
public Date2 (int j, int m, int a)
{
jj = j;
mm = m;
aaaa = a;
}
}
Utilisation de la classe Date2
…
// Provoque
une erreur car il n'existe pas de constructeur sans paramètre
Date d2=new Date2();
1.3. Constructeur surchargé
Il est possible
de surcharger un constructeur de la même façon que l'on peut
surcharger une procédure ou une fonction.
Déclaration de la classe Date2 et
définition de plusieurs constructeurs
import java.util.GregorianCalendar;
class Date2
{
private int jj, mm, aaaa;
public Date2
(int j, int m, int a)
{
jj = j;
mm = m;
aaaa = a;
}
public Date2
()
// Date système
{
GregorianCalendar now = new
GregorianCalendar();
jj = now.get(GregorianCalendar.DAY_OF_MONTH);
mm = now.get(GregorianCalendar.MONTH)+1;
aaaa = now.get(GregorianCalendar.YEAR);
}
}
Le choix du constructeur à appliquer se fait
selon la signature comme c'est le cas pour une fonction ou
procédure surchargée.
On dit qu'une classe possède un
constructeur par défaut s'il est possible de créer une
instance de cette classe sans spécifier de paramètre lors de
l'instanciation.
C'est le cas ici puisque le 2ème
constructeur n'a pas de paramètre.
Quand aucun constructeur n'est défini, il y a
un constructeur par défaut puisqu'il y a le constructeur implicite
généré par Java.
On peut définir un constructeur par défaut
sans y associer d’instructions ; dans ce cas l'objet est créé
comme s'il n'y avait aucun constructeur de défini.
1.4. Appel explicite d'un
constructeur
Le constructeur
peut être appelé de manière explicite par un autre constructeur, on
peut écrire :
class Eleve
{
private String el_nom;
private float el_oral;
private float
el_ecrit;
public Eleve() //constructeur par
défaut
{
this("toto", 0, 0);
System.out.println("Le constructeur avec paramètres a été
appelé");
}
public Eleve(String n, float o, float e)
//constructeur avec paramètres
{
el_nom=n;
el_oral=o;
el_ecrit=e;
}
}
L’appel du
constructeur doit être la première instruction.
Ceci est très
pratique pour donner des valeurs initiales par défaut aux données
membres de l'objet (c'est à dire dans le cas où l'appelant ne les
fournit pas).
1.5. Bien comprendre qu'il n'y a
pas appel au constructeur lors de la simple déclaration d'une
référence
Une référence
désigne ou désignera un objet. Par abus de langage, on peut dire
qu'une référence est un nom via lequel on manipule un
objet.
Exemple : Date
d1; // d1 est un nom
En Java, une
référence est également appelée handle (poignée, ce
qui est évocateur puisque cela sert à manipuler
l'objet).
L'adresse des
objets ne peut être manipulée par les programmeurs, les
programmeurs utilisent les handles pour manipuler les
objets.
Tant que la
référence ne désigne pas d'objet, elle vaut null.
Un objet peut
être désigné par plusieurs références.
Divers
exemples :
Date2 d1 = new
Date2(); // Déclaration de
d1
// Appel au constructeur car new Date2()
Date2 d2 =
d1;
// Déclaration de d2
// Pas d'appel au constructeur
// L'objet créé précédemment est maintenant désigné par 2
références :
// d1 et d2.
Remarque : si je modifie l'objet via d2, les
modifications seront bien sûr visibles via d1 ou d2.
// Méthode
statique noel qui retourne l'objet date initialisé au 25 décembre
de l'année
// Méthode qui
reçoit un objet (en fait une référence sur un objet) de classe
Date2
void proc
(Date2
d)
// Pas d'appel au constructeur
{
...
}
Date2 d4 = new
Date2();
// Appel au constructeur
proc
(d4);
// Transmission d'une référence sur l'objet
Si j'applique une méthode de mise à jour
sur d dans proc, je modifie l'objet transmis. En effet, un objet
est transmis par référence (c'est également le cas pour un tableau)
contrairement aux données de type élémentaire qui sont toujours
transmises par valeur.
2. DESTRUCTION DES OBJETS
La mémoire
nécessaire à la mémorisation de tout nouvel objet est allouée
dynamiquement à sa création. Ce n'est pas le programmeur qui gère
la libération de la mémoire des objets devenus inaccessibles (un
objet est inaccessible quand il n'est plus référencé par aucune
variable du programme).
Cette
libération est réalisée grâce au Garbage Collector (Ramasseur
d'Ordure ou Ramasse miettes) fourni avec la Machine Virtuelle Java.
C'est un processus qui se lance dès qu'on descend en-dessous d'un
certain seuil de mémoire disponible et qui :
. récupère la
mémoire occupée par les objets devenus inaccessibles,
. compacte la
mémoire disponible.
La durée de
validité d'une référence est liée à sa portée mais le programmeur
peut tout de même indiquer à la Machine Virtuelle qu'une
référence var1 désignant un objet n'est plus utile en la
mettant à null (var1
= null;),
3. PARTICULARITES
3.1. Objet membre d'une
classe
Considérons une
classe représentant les jours fériés :
3.2.
Tableaux d'objets
Le constructeur
peut être appelé pour construire chaque objet du tableau lors de la
déclaration du tableau ou après la déclaration du
tableau.
Exemple :
class
Prog1tab
{
public static void main(String argv[])
{
Date2 d1=new Date2(5,2,2001);
// Déclaration et
initialisation d'un tableau d'objets Date2 (les différents cas
possibles
// sont représentés : nouvel objet construit sans ou avec
paramètres, référence sur objet
// existant et null)
Date2 [] tabdate ={ new Date2(), d1, new
Date2(20,10,2001), null};
Date2[] tabdate2
= new Date2[3];
tabdate2[0] = new Date2();
tabdate2[1] = new Date2(10,11,2001);
tabdate2[2] = new Date2(20,10,2001);
int i;
for ( i=0;i<3;i++)
tabdate[i].affich();
for (
i=0;i<3;i++)
tabdate2[i].affich();
}
}