2. CLASSES ET HERITAGE
 
 
VARIABLE OBJET
 

Comme en C++, il existe en Java deux types de variables, celles qui font référence à des types primitifs (int, char, double...) et celles qui représentent des objets. La sémantique concernant les variables de type primitif en Java est identique à celle du C++. En revanche, les variables objets ont une signification bien différente.

 
Référence ou pointeur ?
 

Il est dit qu'en Java il n'existe pas de pointeurs et que toutes les variables objets sont des références sur des objets. Pour des personnes programmant en C++, le terme "référence" a une signification bien précise qui le différencie du terme "pointeur". En Java, le terme "référence" correspond en fait au terme "pointeur" du C++, à la seule différence qu'il est impossible pour le programmeur de manipuler explicitement l'adresse encapsulée dans le pointeur (i.e. impossible d'afficher l'adresse ou d'effectuer une opération arithmétique). Considérons l'exemple suivant qui déclare une variable s de la classe String.

String s;

La variable est initialisée implicitement à null, indiquant qu'elle ne référence aucun objet. A ce moment donc, aucun objet de la classe String n'est créé.

 
Création d'un objet
 

La création d'un objet doit être demandée explicitement par le programmeur, grâce au mot-clé new.

s = new String("hello !");

Comme en C++, new permet de passer des paramètres au constructeur de la classe String. L'exemple suivant montre également que les variables en Java sont des pointeurs.

void traduire(String t) { t=new String("Bonjour !"); }
...
String s = new String("Hello !");
traduire(s);

Les arguments des méthodes sont toujours passés par copie, ainsi le pointeur s (ou la référence s) est copiée, et c'est sa copie locale t qui référence la chaîne "Bonjour !". La variable s reste donc inchangée après l'appel à la méthode traduire.

 
Accès aux propriétés d'un objet
 

Toutes les variables objets étant des pointeurs en Java, il n'est plus nécessaire, contrairement à C++, de faire la différence entre -> et . pour appeler une méthode. En Java, seul le symbole . est utilisé pour appeler une méthode. L'exemple suivant appelle la méthode length de l'objet s.

int taille = s.length();

 
Destruction d'un objet
 

Toutes les variables étant finalement allouées dynamiquement, il serait fastidieux d'effectuer manuellement toutes les libérations de mémoire. Un mécanisme automatique, le ramasse-miettes (ou garbage collector), se charge de libérer les objets une fois qu'ils ne sont plus référencés par aucune variable. L'inconvénient ou l'avantage, selon les personnes, de cet automatisme est que le programmeur n'a aucune idée du moment où les objets sont libérés et donc de l'appel au destructeur. En effet, le ramasse-miettes n'est pas obligé de libérer la mémoire tout de suite, il peut très bien attendre d'avoir besoin de ressources pour effectuer un nettoyage.

 
DEFINITION D'UNE CLASSE
 
 
Syntaxe
 

La syntaxe pour définir une classe en Java est très proche de celle employée en C++. Le plus simple pour la présenter est tout simplement de montrer un exemple.

class Personne {
 // Attributs privés d'instance
 protected int numero;
 protected String nom;
 protected String prenom;

 // Attribut privé de classe
 protected static int compteur = 0;

 // Constante
 public static final int MAX = 100;

 // Méthodes publiques d'instance
 public int getNumero() { return numero; }
 public String getNom() { return nom; }
 public String getPrenom() { return prenom; }

 // Constructeur
 public Personne(String n,String p) {
  nom=n;
  prenom=p;
  numero=++compteur;
 }

 // Destructeur
 protected void finalize() {}

 // Méthodes publiques de classe
 public static int getNbPersonne() { return compteur; }
 public static void main(String args[]) { ... }
}

Les mots clés public et protected permettent respectivement de déclarer une propriété publique ou privée. Comme en C++, static permet de définir des propriétés de classe. La combinaison static final permet de définir des constantes. Le constructeur porte le nom de la classe, et bien entendu, il peut y en avoir plusieurs. Le destructeur lui porte le nom finalize. Il est conseillé de le déclarer uniquement s'il est nécessaire de l'employer, ce qui est très rare du fait que la libération de la mémoire est gérée automatiquement par le ramasse-miettes.

 
La méthode main
 

Lors de l'exécution d'un fichier, la JVM appelle la méthode main de la classe publique du fichier. Si cette méthode n'existe pas, l'exécution échoue. En paramètre, la méthode main reçoit un tableau de chaînes de caractères qui correspondent aux arguments de la ligne de commande, de manière similaire à C++ (cf. l'exemple de la classe Personne).

 
La super-classe Object
 

Avec Java, une classe définie sans super-classe hérite systématiquement de la classe Object qui se trouve ainsi au sommet de la hiérarchie d'héritage. Toute classe en Java hérite, directement ou indirectement, de cette classe Object. Nous verrons l'intérêt de cette classe au chapitre suivant.

 
HERITAGE
 
 
Héritage simple et méthodes virtuelles
 

Java n'autorise que l'héritage simple grâce au mot clé extends. L'héritage multiple n'est pas autorisé, à cause des nombreuses ambiguïtés qu'il soulève. Pour permettre néanmoins cette modélisation, la notion d'interface a été introduite, nous la présentons dans le dernier chapitre. Considérons l'exemple suivant d'héritage où la classe Cercle hérite de la classe Forme.

class Forme {
 protected float x;
 protected float y;

 public Forme(float a,float b) {
  x=a;
  y=b;
 }

 public float aire() { return 0.0; }
}

class Cercle extends Forme {
 protected float rayon;
 protected static final float PI = 3.1415;

 public Cercle(float a,float b,float r) {
  super(a,b);
  rayon=r;
 }

 public float aire() { return (PI*rayon*rayon); }
}

Contrairement au C++, les méthodes sont virtuelles par défaut en Java. Dans l'exemple, la méthode aire est donc virtuelle et redéfinie dans la classe Cercle.

 
Appel à la super-classe
 

Le mot-clé super représente la super-classe de la classe dans laquelle on se trouve (il n'y en a qu'une puisqu'il n'y a pas d'héritage multiple). Ainsi, dans l'exemple avec la classe Forme, le constructeur Cercle appelle le constructeur de la classe Forme grâce à super(...). Il est également possible pendant la redéfinition d'une méthode d'appeler la version de la super-classe, comme le montre l'exemple suivant.

class Personne {
 protected String nom;
 protected String prenom;
 ...
 public String getInfo() { return (nom+" "+prenom); }
}

class Employe extends Personne {
 protected String poste;
 ...
 public String getInfo() { return (super.getInfo()+" "+poste); }
}

 
Méthodes finales
 

Le mot-clé final permet de rendre une méthode finale, i.e. non virtuelle, elle ne peut donc pas être redéfinie. Il est conseillé de rendre les accesseurs (i.e. les méthodes get... et set... qui permettent de manipuler les attributs) finaux, l'appel à une méthode virtuelle étant une opération très coûteuse en comparaison avec l'appel à une méthode finale. Ainsi, dans l'exemple de la section précédente, il faut plutôt déclarer:

 public final int getNumero() { return numero; }
 public final String getNom() { return nom; }
 public final String getPrenom() { return prenom; }

 
Méthodes abstraites
 

Il est possible de définir des méthodes abstraites, i.e. sans corps, grâce au mot-clé abstract. L'exemple de la classe Forme est modifié pour proposer la méthode aire abstraite.

abstract class Forme {
 protected float x;
 protected float y;

 public Forme(float a,float b) {
  x=a;
  y=b;
 }

 public abstract float aire();
}

class Cercle extends Forme {
 protected float rayon;
 protected static final float PI = 3.1415;

 public Cercle(float a,float b,float r) {
  super(a,b);
  rayon=r;
 }

 public float aire() { return (PI*rayon*rayon); }
}

Dans ce cas, la classe Forme est abstraite également, ce qui signifie qu'elle ne peut pas être instanciée, aucun objet purement de cette classe ne peut être créé.

 
 
Copyright (c) 1999-2016 - Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
La permission est accordée de copier, distribuer et/ou modifier ce document sous les termes de la licence GNU Free Documentation License, Version 1.1 ou toute version ultérieure publiée par la fondation Free Software Foundation. Voir cette licence pour plus de détails (http://www.gnu.org).