Maintenant que nous avons créé des modules avec succès, nous pouvons approfondir la déclaration de module. Dans ces sections, nous examinerons exports
, requires
, et opens
. Dans la section suivante sur les services, nous explorerons provides
et uses
. C’est le bon moment pour mentionner que ces directives peuvent apparaître dans n’importe quel ordre dans la déclaration du module.
Exportation d’un Package
Nous avons déjà vu comment exports packageName
exporte un package vers d’autres modules. Il est également possible d’exporter un package vers un module spécifique. Supposons que le zoo décide que seuls les membres du personnel devraient avoir accès aux conférences. Nous pourrions mettre à jour la déclaration du module comme suit :
module zoo.animal.talks {
exports zoo.animal.talks.content to zoo.staff;
exports zoo.animal.talks.media;
exports zoo.animal.talks.schedule;
requires zoo.animal.feeding;
requires zoo.animal.care;
}
Du point de vue du module zoo.staff
, rien n’a changé. Cependant, aucun autre module ne serait autorisé à accéder à ce package.
Vous avez peut-être remarqué qu’aucun de nos autres modules ne requiert zoo.animal.talks
en premier lieu. Cependant, nous ne savons pas quels autres modules existeront à l’avenir. Il est important de considérer l’utilisation future lors de la conception des modules. Puisque nous voulons que seul ce module ait accès, nous n’autorisons l’accès que pour ce module.
Types Exportés
Nous avons parlé d’exporter un package. Mais qu’est-ce que cela signifie exactement ?
Toutes les classes public
, interfaces, enums et records sont exportés. De plus, tous les champs et méthodes public
et protected
dans ces fichiers sont visibles.
Les champs et méthodes qui sont private
ne sont pas visibles car ils ne sont pas accessibles en dehors de la classe. De même, les champs et méthodes de package ne sont pas visibles car ils ne sont pas accessibles en dehors du package.
La directive exports
nous donne essentiellement plus de niveaux de contrôle d’accès. Le Tableau 12.3 liste les options complètes de contrôle d’accès.
Niveau | Dans le code du module | En dehors du module |
---|---|---|
private | Disponible uniquement dans la classe | Pas d’accès |
Package | Disponible uniquement dans le package | Pas d’accès |
protected | Disponible uniquement dans le package ou les sous-classes | Accessible aux sous-classes uniquement si le package est exporté |
public | Disponible pour toutes les classes | Accessible uniquement si le package est exporté |
Requérir un Module de Manière Transitive
Comme vous l’avez vu plus tôt dans ce chapitre, requires moduleName
spécifie que le module actuel dépend de moduleName
. Il existe également requires transitive moduleName
, qui signifie que tout module qui requiert ce module dépendra également de moduleName
.
Voyons un exemple. La Figure 12.12 montre les modules avec des lignes pointillées pour les relations redondantes et des lignes continues pour les relations spécifiées dans le module-info
. Cela montre comment les relations de module apparaîtraient si nous n’utilisions que des dépendances transitives.
Par exemple, zoo.animal.talks
dépend de zoo.animal.care
, qui dépend de zoo.animal.feeding
. Cela signifie que la flèche entre zoo.animal.talks
et zoo.animal.feeding
n’apparaît plus dans la Figure 12.12.
Examinons maintenant les quatre déclarations de module. Le premier module reste inchangé. Nous exportons un package vers tous les packages qui utilisent le module.
module zoo.animal.feeding {
exports zoo.animal.feeding;
}
Le module zoo.animal.care
est la première opportunité d’améliorer les choses. Plutôt que de forcer tous les modules restants à spécifier explicitement zoo.animal.feeding
, le code utilise requires transitive
.
module zoo.animal.care {
exports zoo.animal.care.medical;
requires transitive zoo.animal.feeding;
}
Dans le module zoo.animal.talks
, nous faisons un changement similaire et ne forçons pas les autres modules à spécifier zoo.animal.care
. Nous n’avons également plus besoin de spécifier zoo.animal.feeding
, donc cette ligne est commentée.
module zoo.animal.talks {
exports zoo.animal.talks.content to zoo.staff;
exports zoo.animal.talks.media;
exports zoo.animal.talks.schedule;
// plus nécessaire requires zoo.animal.feeding;
// plus nécessaire requires zoo.animal.care;
requires transitive zoo.animal.care;
}
Enfin, dans le module zoo.staff
, nous pouvons nous débarrasser de deux instructions requires
.
module zoo.staff {
// plus nécessaire requires zoo.animal.feeding;
// plus nécessaire requires zoo.animal.care;
requires zoo.animal.talks;
}
Plus vous avez de modules, plus les avantages du composé requires transitive
sont importants. C’est également plus pratique pour l’appelant. Si vous essayiez de travailler avec ce zoo, vous pourriez simplement demander zoo.staff
et avoir les dépendances restantes automatiquement déduites.
Effets de requires transitive
Étant donné nos nouvelles déclarations de module, et en utilisant la Figure 12.12, quel est l’effet de l’application du modificateur transitive
à l’instruction requires
dans notre module zoo.animal.care
? L’application des modificateurs transitifs a les effets suivants :
- Le module
zoo.animal.talks
peut éventuellement déclarer qu’il requiert le modulezoo.animal.feeding
, mais ce n’est pas obligatoire. - Le module
zoo.animal.care
ne peut pas être compilé ou exécuté sans accès au modulezoo.animal.feeding
. - Le module
zoo.animal.talks
ne peut pas être compilé ou exécuté sans accès au modulezoo.animal.feeding
.
Ces règles s’appliquent même si les modules zoo.animal.care
et zoo.animal.talks
ne référencent pas explicitement des packages dans le module zoo.animal.feeding
. D’autre part, sans le modificateur transitive
dans notre déclaration de module de zoo.animal.care
, les autres modules devraient utiliser explicitement requires
pour référencer des packages dans le module zoo.animal.feeding
.
Instructions requires dupliquées
Un endroit où vous pourriez être piégé est en mélangeant requires
et requires transitive
. Pouvez-vous penser à une raison pour laquelle ce code ne compile pas ?
module bad.module {
requires zoo.animal.talks;
requires transitive zoo.animal.talks;
}
Java ne vous permet pas de répéter le même module dans une clause requires
. C’est redondant et probablement une erreur de codage. Gardez à l’esprit que requires transitive
est comme requires
plus un comportement supplémentaire.
Ouverture d’un Package
Java permet aux appelants d’inspecter et d’appeler du code au moment de l’exécution avec une technique appelée réflexion. C’est une approche puissante qui permet d’appeler du code qui pourrait ne pas être disponible au moment de la compilation. Elle peut même être utilisée pour contourner le contrôle d’accès !
La directive opens
est utilisée pour activer la réflexion d’un package dans un module. Vous devez seulement être conscient que la directive opens
existe plutôt que de la comprendre en détail.
Comme la réflexion peut être dangereuse, le système de modules oblige les développeurs à autoriser explicitement la réflexion dans la déclaration du module s’ils veulent que les modules appelants soient autorisés à l’utiliser. Voici comment activer la réflexion pour deux packages dans le module zoo.animal.talks
:
module zoo.animal.talks {
opens zoo.animal.talks.schedule;
opens zoo.animal.talks.media to zoo.staff;
}
Le premier exemple permet à tout module utilisant celui-ci d’utiliser la réflexion. Le deuxième exemple ne donne ce privilège qu’au module zoo.staff
. Il existe deux autres directives que vous devez connaître : provides
et uses
, qui sont couvertes dans la section suivante.
Scénario du Monde Réel
Ouverture d’un Module Entier
Dans l’exemple précédent, nous avons ouvert deux packages dans le module zoo.animal.talks
, mais supposons que nous voulions plutôt ouvrir tous les packages pour la réflexion. Pas de problème. Nous pouvons utiliser le modificateur de module open
, plutôt que la directive opens
(notez la différence du s) :
open module zoo.animal.talks {
}
Avec ce modificateur de module, Java sait que nous voulons que tous les packages du module soient ouverts. Que se passe-t-il si vous appliquez les deux ensemble ?
open module zoo.animal.talks {
opens zoo.animal.talks.schedule; // NE COMPILE PAS
}
Cela ne compile pas car un modificateur qui utilise le modificateur open
n’est pas autorisé à utiliser la directive opens
. Après tout, les packages sont déjà ouverts !