Page précédenteIndexPage suivante

CHAPITRE 7 - Les spécificateurs et les packages

Les spécificateurs sont les mots clés associés aux classes, variables et méthodes pour leur octroyer certaines propriétés. Ils sont utilisés pour limiter les accès ou pour attribuer des possibilités ou restrictions spécifiques: statique, constant, non-modifiable, privée... pour une variable ou une méthode, non dérivable, abstraite... pour une classe. Ce chapitre abordera ensuite les packages qui permettent de constituer les arborescences des applications.

7.1- Spécificateurs et gestion des classes

Définition

Les spécificateurs sont des mots clés qui définissent tour à tour les droits d'accès d'une variable, d'une méthode ou leur caractère statique. Ils se placent en tête de code. C'est donc le premier élément qui est écrit lors des définitions des variables ou des méthodes:

Spécificateur(s) Type variable;
Spécificateur(s) Type_Renvoyé méthode ( arguments );

Exemple :

static final String sTest="toto";
private Integer;

Tableau récapitulatif des spécificateurs de variable, de méthode, de classe:


Propriété

Méthode

Classe

public

La variable est visible par n'importe quelle classe du package ou extérieure au package.

La méthode est visible de n'importe quelle classe.

Peut être dérivée par des classes de tout package

private

La variable n'est visible que dans la classe courante. 

( non visible même des classes filles ) 

La méthode n'est applicable que dans la classe courante.

Pas de sens

protected

Le variable n'est visible que par la classe, ses filles et les autres classes du package ainsi que leurs filles 

La méthode n'est utilisable que par la classe, ses sous classes du même package ou de packages différents  et les autres classes du package ainsi que leurs filles

Pas de sens

static

La variable est dite "variable de classe".
Si la variable d'une instance de cette classe  est modifiée, toutes les instances de l'objet sont automatiquement modifiées. Ainsi, la variable ne dépend pas de l'instance courante mais de la classe. Il est possible d'y accéder directement par la classe:
MaClasse mc=new MaClasse(); 
on peut accéder par:
MaClasse.maPropriété (préféré)
ou mc.maPropriété

La méthode est dite "méthode de classe" . Elle est définie une seule fois pour toutes les instances. Il est possible de l'appeler directement par la classe:
MaClasse mc=new MaClasse(); 
on peut appeler MaClasse.maMéthode(); (préféré)
ou mc.maMéthode ();

Pas de sens

final 

La variable est non modifiable dans l'instance courante. Elle doit donc être initialisée.

Si on ajoute le mot clé "static", la variable est une constante de classe:

static final int i=2;

La méthode ne peut être surchargée dans une sous-classe

La classe ne peut pas avoir de classes filles. L'extends est interdit.

abstract

Pas de sens

Non applicable à une variable, uniquement les méthodes.

La méthode est simplement définie dans une classe abstraite, doit être implémentée dans toutes les classes filles:

abstract public String maMéthode();

La classe contient au moins une méthode abstraite.


Par défaut

Lorsque l'on ne précise rien: 

Remarques:



7.2- Les packages

Nous discuterons des arborescences logiques et physiques des classes Java.

Définition

Pour simplifier l'organisation des fichiers .class, il est possible de spécifier en début de source que les classes implémentées font partie d'un package, c'est-à-dire d'un ensemble de classes regroupées de façon fonctionnelle. Il suffit d'utiliser le mot clé package. Exemple dans un fichier .java:

package vehicule;
    public class Voiture{
       ...
    }
    class Moto{
       ...
    }
}

Dans un autre fichier :
package vehicule;
    public class Camion{
       ...
    }
}

Il faut que les classes soient physiquement dans le même répertoire à l'exécution. De plus, les sous-packages sont possibles:

package vehicule.voiture;
public class VoitureEssence{
}
class VoitureDiesel{
}

Physiquement les fichiers seront:

<...>/vehicule/voiture/VoitureEssence.class
<...>/vehicule/voiture/VoitureDiesel.class

Le nom complet d'une classe est donné par les noms des packages et sous packages de la classe + le nom de la classe, par exemple java.lang.Object. Le package le plus utilisé de Java est java.lang qui contient les classes de base ( dont la classe Object ) .

Norme SUN

Noms de package normalisés SUN :

Par exemple le package mycompany.tutorial.exemples contiendra la classe mycompany.tutorial.exemples.Voiture.


7.3- Les classes importées

La plupart du temps, une classe utilise des objets d'une autre classe. Dès lors, il y a plusieurs cas:

 Le mot clé est import. En début de source, avant la définition de la classe et après la déclaration du package, il faut importer les classes que l'on va utiliser:

package toto;
import java.util.*;        // importe toutes les classes du package java.util
import vehicule.Moto;   //importe la classe Moto seule
class titi{ ...
}

Dès lors, la classe accède aux méthodes et variables de ces classes importées.

Remarques



7.4- La gestion physique des sources et classes

Les sources

Le fait de programmer en langage Objet conduit à la gestion de nombreux fichiers. En général, à une source .java correspond une classe mais il est possible - bien que dangereux - de définir plusieurs classes dans une même source à condition de n'en déclarer qu'une seule de type public ( les autres sont des classes dites outer ). En effet, si une classe est déclarée publique, elle doit figurer dans un fichier portant son nom et un fichier ne peut avoir qu'un nom. Il est également possible de définir une classe à l'intérieur d'une autre classe ( inner class ). Dans ce cas,après compilation, nous obtiendrons plusieurs fichiers .class

Les fichiers jar

Étant donné que les contraintes hardware actuelles se portent davantage sur la taille des paquets transmis via un réseau que sur la vitesse des processeurs, les packages sont souvent compressés ( à la façon des .zip ) et forment des fichiers .jar qui sont décompressés à la volée à l'utilisation des classes.

Utilisation des jars

Le package vehicule.* correspondant à toutes les classes situées récursivement dans ce répertoire peut être compressé en un fichier vehicule.jar. Pour compresser un répertoire dir recursivement en un fichier monjar.jar, lancez la commande :

jar cvf monjar.jar dir

Pour le décompresser :

jar xvf monjar.jar 

La JVM Java "voit" un jar comme un répertoire et non comme un fichier. Nous trouvant dans un répertoire contenant un fichier tutorial.jar qui contient la classe mycompany.tutorial.Classe1.class , nous ferons :

java mycompany.tutorial.Classe1 

Le CLASSPATH

Nous avons vu que les classes Java de différents packages parvenaient à se "connaître" entre elles grâce à la commande import. Cependant du point de vue de l'environnement système, les classes et les jars se trouvent dans des emplacements physiques pouvant être différents de l'emplacement courant. Dans les sources Java, les imports sont faits sur des classes se trouvant dans des emplacements "logiques"; il faut en plus indiquer au système l'emplacement de ces classes. C'est pourquoi il faut que l'environnement au moment du lancement du programme ait la variable d'environnement CLASSPATH correctement définie. La variable CLASSPATH contiendra les chemins des classes importées dans les programmes.

Sous UNIX, utiliser la commande :

export CLASSPATH=[nom des répertoires] : [nom des fichiers.jar] : $CLASSPATH

Exemple:

export CLASSPATH=.:/tmp/tutorial/exemples:/tmp/tutorial.jar:$CLASSPATH

Attention, les séparateurs sont des ':'

Sous Microsoft DOS, utiliser la commande

set CLASSPATH=[nom des répertoires] ; [nom des fichiers.jar] ; %CLASSPATH%

Attention, les séparateurs sont des ';'

Pour permettre l'import des classes d'un répertoire, il faut donner le nom du répertoire. Nous pourrons alors importer toutes les classes de ce répertoire et de ses sous-répertoires. Cependant, pour permettre l'import des classes d'un jar, il faut poser le chemin complet du jar et pas seulement le nom du répertoire dans lequel il se trouve. Il faut veiller à toujours avoir le répertoire courant '.' dans son CLASSPATH. En lançant un programme, le CLASSPATH doit au moins contenir le jar contenant le système Java de base ($JAVA_HOME/jre/lib/rt.jar en général). Il peut être utile d'avoir également $JAVA_HOME/jre/lib/tools.jar.

Remarque: Sur la plupart des Unices ( Linux, AIX, Solaris...), le programme 'java' est un shell qui inclus lui-même '.' et 'rt.jar' dans le CLASSPATH.

La documentation par javadoc

Lorsque le projet devient conséquent, il faut recourir à une documentation exhaustive et tenue à jour des classes, ce qui pourrait sembler impossible sans l'outil du JDK javadoc. Cet outil permet de générer une documentation complète et très aboutie en HTML du projet complet en quelques secondes. Il sera nécessaire de normaliser certaines partie du code (commentaires) pour obtenir des commentaires additionnels dans la documentation automatique. Pour les commentaires de méthodes, il suffit de procéder comme il suit:

/**
* Ligne 1
* Ligne 2
**/

Cf. la documentation SUN pour plus de détails sur javadoc.




TD7 - Les spécificateurs et les packages

Exercice 1: Utilisation des spécificateurs

Écrire la classe mycompany.tutorial.TestSpecif possédant:

- La variable i1 accessible  par toutes les autres classes et valant 10.

- La variable i2 accessible  que par la classe TestSpecif elle-même et valant 20

- La variable i3 ne pouvant  être accédée que dans le package ou les classes filles et valant 30.

- La méthode m1() statique et qui ne peut être surchargée mais qui est utilisable par toutes les classes. Cette méthode affiche i1 sur la sortie standard.

- La méthode m2() qui n'est utilisable que dans TestSpecif et qui ajoute 10 à i2

- La méthode m3() qui est abstraite et renvoie void.

1- Compilez puis corrigez le message que vous devez obtenir, l'expliquer.

2- Écrire une méthode getI2() qui renvoie la valeur de i2. Cette méthode sera publique. Comment appelle-t-on ce type de méthode?

3- Écrire une méthode setI2(int) qui fixe la valeur de i2. Cette méthode sera publique. Comment appelle-t-on ce type de méthode?

Exercice 2 : Bloquer l'héritage

Écrire la classe mycompany.tutorial.TestSpecifFille, dérivée de la classe TestSpecif.

1- Cette classe ne doit pas pouvoir être dérivée. Comment procéder?

2- Tenter de surcharger m1(). Que se passe-t-il? Pourquoi? 

3- Écrire deux méthodes :

- m4() qui ajoute 10 à la variable i2 de TestSpécif. Pourquoi y a-t-il une erreur de compilation? Essayer avec i3. Est-ce mieux? pourquoi?

- Implémenter m3() qui était une méthode abstraite et qui doit afficher i3 sur la sortie standard. 

Exercice 3 : Pour en finir avec les spécificateurs...

Ajouter une méthode main() dans la classe TestSpecifFille qui affiche à l'écran les variables i1, i2 (avec  getI2() ) et i3.

Attention la méthode main() a quelques particularités. Bien réfléchir aux impacts... 

Exercice 4 : Utilisation des packages et des jar

Dans cet exemple, les classes seront vides et définies comme ci-après:

class X{
}

1- Créer le package mycompany.tutorial.exemples1 qui contient les classes mycompany.tutorial.exemples1.Classe1 et mycompany.tutorial.exemples1.Classe2

2- Créer le package mycompany.tutorial.exemples2 qui contient la classe mycompany.tutorial.exemples2.Classe1

3- En admettant que les sources de ces classes se trouvent dans un répertoire quelconque et que l'on lance javac *.java, où se trouvent les classes compilées?

Lancer l'une de ces classes. Que se passe-t-il et pourquoi? Comment faut-il organiser les sources et les classes pour faciliter le développement puis permettre à l'application de fonctionner?

4- Dans la classe mycompany.tutorial.exemples1.Classe1 , implémenter une méthode main() qui affiche "Test". Comment lancez-vous cette classe? 

5- Compresser l'arborescence mycompany en tutorial.jar par la commande jar. Puis consultez le contenu à l'aide d'un utilitaire de compression comme gzip ou winzip, que constatez vous ? Quelle est l'avantage de cette méthode ?



solutions





Page précédenteIndexPage suivante