Organisation d'un programme
On va maintenant s'intéresser à la manière d'organiser un programme. Pour rappel, en Java, tout se définit à partir de classes qui contiennent des définitions de variables d'instance et de méthodes. Ces différents éléments sont organisés en package et possèdent une certaine visibilité. Cette section traite de ces différents sujets.
Définition de package
On a vu à la section 4.5 que les packages sont utilisés pour organiser les classes et permettent également de définir leurs noms qualifiés complets. Maintenant qu'on a vu comment définir ses propres classes, on peut également vouloir définir ses propres packages.
Pour ce faire, il suffit d'ajouter une déclaration de package dans le code source de la classe. Une telle déclaration consiste en le mot réservé package
suivi du nom de package désiré et d'un point-virgule.
L'exemple suivant définit une classe Square
qu'on définit comme faisant partie du package geom
:
Le nom qualifié complet de la classe définie est donc geom.Square
. Pour pouvoir l'utiliser dans une autre classe, il faut donc soit utiliser son nom qualifié complet, soit importer la classe avec une déclaration d'import.
Toutes les classes ne contenant pas de déclaration de package font implicitement partie d'un package appelé le package par défaut. Les classes du package par défaut ne sont utilisables que depuis ce même package, il est en effet impossible de les importer.
Modificateur de visibilité
Une fois les classes organisées en package, il faut choisir leur visibilité. Toutes les classes qu'on a vues jusqu'à présent étaient déclarées public
. Il y a en fait deux niveaux de visibilité différents : publique et package. Pour déclarer une classe avec une visibilité publique, il suffit d'utiliser le mot réservé public
lors de sa déclaration et pour la visibilité package, il suffit de ne mettre aucune modificateur. La classe suivante possède la visibilité package, aussi appelée visibilité par défaut :
La visibilité d'une classe identifie les endroits d'un programme à partir desquels la classe est visible, c'est-à-dire qu'il est possible de créer des instances de celle-ci, ou d'accéder à ses membres de classes. Partons d'un exemple pour comprendre ce principe. La figure 24 montre trois classes organisées dans deux packages.
Supposons qu'on se trouve dans la classe A
du package pb
. Tout ce qu'on voit depuis cette classe, c'est la classe A
du package pa
. La classe B
du package pa
n'est pas visible. Par contre, si on se trouve dans la classe A
du package pa
, on voit toutes les trois classes.
La règle est simple : une classe publique est visible depuis tout l'univers Java (Appelé Java Universe (JU) en anglais), tandis qu'une classe avec la visibilité par défaut ne l'est que depuis les classes du package dans lequel elle se trouve.
À quoi peut bien servir la visibilité par défaut ? Supposons que vous souhaitez définir une nouvelle classe et qu'il judicieux de le faire par composition de plusieurs autres classes. Néanmoins, vous ne voulez pas exposer cette décomposition au monde extérieur. Pour ce faire, il suffit de ne déclarer que la classe principale publique et de donner la visibilité par défaut à toutes les autres.
Les membres des classes (méthodes et variables d'instance) possèdent également une certaine visibilité. Il y a quatre niveaux de visibilité possibles pour les membres d'une classe et on va en voir trois tout de suite, le quatrième sera vu au chapitre 9. La visibilité d'un membre peut-être publique (public
), privée (private
) ou par défaut. Celle-ci permet de contrôler depuis quelles classes il est possible d'accéder à ces membres en utilisant l'opérateur d'accès ( .
).
Les membres publics sont accessibles depuis tout l'univers Java et les membres privés ne sont accessibles que depuis la classe dans laquelle ils sont déclarés. Enfin, les membres avec la visibilité par défaut ne sont accessibles que depuis les classes faisant partie du même package que la classe les contenant. Pour pouvoir accéder à un membre d'une classe, il faut avant tout avoir une référence vers une instance de la classe et il faut donc que celle-ci soit visible.
Repartons à nouveau d'un exemple pour comprendre la visibilité des membres. La figure 25 montre une classe A
dans un package pa
. Elle possède trois variables d'instance a
, b
et c
qui ont respectivement une visibilité publique, par défaut et privée.
La variable d'instance c
étant privée, on ne pourra y accéder que depuis la classe A
du package pa
. La variable d'instance b
possède la visibilité par défaut et on pourra donc y accéder depuis toutes les classes du package pa
. Enfin, la variable d'instance a
pourra être accédée depuis toutes les classes. La règle est exactement la même pour les méthodes.
Fichier source
Voyons maintenant quelles sont les contraintes liées à l'écriture du fichier source d'un programme. Dans un tel fichier, on retrouve trois éléments qui doivent obligatoirement apparaitre dans l'ordre suivant :
- déclaration de package ;
- déclarations d'import ;
- définition de la classe.
Cet ordre est imposé et si vous ne le respectez pas, vous ferez face à une erreur de compilation. Prenons par exemple le fichier source suivant :
La déclaration de package ne se trouve pas au bon endroit. Elle doit absolument apparaitre en première position dans le fichier source. La compilation de ce fichier produit une erreur indiquant qu'un élément est attendu à un endroit où il ne se trouve pas :
BankAccount.java:3: class, interface, or enum expected package bank; ^ 1 error
Les trois éléments sont optionnels. Il est possible de définir plusieurs classes dans un même fichier pour autant que certaines contraintes soient respectés. Il ne peut y avoir qu'une seule classe publique au maximum et autant de classes avec la visibilité par défaut que l'on souhaite. Si le fichier possède une classe publique, son nom doit être le même que celui de la classe. Si le fichier ne contient pas de classe publique, on peut lui donner le nom qu'on veut. Dans les deux cas, l'extension du fichier doit être .java
.
Il faut ensuite définir chacune des classes. Le corps de chaque classe est composé de déclaration de membres. Il n'y a aucune contrainte sur l'ordre dans lequel les membres doivent être placés dans le corps de la classe. Voici comment on pourrait définir une classe BankAccount
représentant un compte bancaire :
Cette classe n'est pas très lisible, mais elle est tout à fait valide et compile sans problème. On verra néanmoins à la section suivante qu'il y a des conventions qu'on peut suivre pour écrire des programmes clairs.
Méthode privée
Terminons cette section en voyant les méthodes privées. Pour rappel, ces méthodes ne pourront être appelées que depuis le corps de la classe contenant leur définition. À quoi peut bien servir une telle méthode ? En fait, on va les utiliser comme méthode auxiliaire utilisée pour rendre le code plus lisible. On verra comment et dans quel cas utiliser de telles méthodes au chapitre suivant.