Créer des packages personnalisés en Java
Créez vos propres packages Java : structure de répertoires, déclaration package et compilation.
Lire les packages des autres est une chose. Créer les vôtres ne demande que trois petites étapes : choisir un nom, organiser le répertoire et placer la bonne déclaration package en haut de chaque fichier. Le compilateur et la JVM s'accordent sur une convention stricte, et une fois que vous l'avez appliquée deux fois, cela devient un réflexe. Si vous découvrez la notion de packages, commencez par l'aperçu Java packages ; ce chapitre se concentre sur la création des vôtres.
Les trois règles
Tout ce que vous écrivez à l'intérieur d'un package doit respecter exactement trois règles :
- La première instruction non commentée du fichier est la déclaration
package. Aucune autre instruction ne peut la précéder. - Le chemin du fichier reflète le nom du package.
com.example.util.Stringsdoit se trouver àcom/example/util/Strings.javasous une racine source. - Le fichier porte le nom de sa classe publique de premier niveau.
Strings.javapourpublic class Strings.
C'est tout. Tout le reste relève de la convention.
Choisir un nom de package
Le compilateur n'impose que les trois règles ci-dessus, mais quelques conventions de nommage permettent de garder vos packages sans collision et idiomatiques :
- Tout en minuscules.
com.w3docs.greet, jamaiscom.W3Docs.Greet. Les lettres majuscules dans les noms de packages fonctionnent mais brisent la convention que tout développeur Java attend, et elles posent des problèmes sur les systèmes de fichiers insensibles à la casse. - Inversez votre nom de domaine. Si vous possédez
w3docs.com, vos packages commencent parcom.w3docs. Cela garantit une unicité globale afin que votreGreetern'entre jamais en conflit avec celui de quelqu'un d'autre sur le classpath. - Pas de mots-clés Java. Un segment de package ne peut pas être un mot réservé. Si votre domaine était
int.example.com, vous ne pourriez pas écrirecom.example.int— vous l'échappez, par exemplecom.example.int_. - Pas de chiffre en tête d'un segment.
com.3m.tapeest illégal car3mn'est pas un identifiant valide ; une correction courante estcom._3m.tape.
Si vous ne déclarez aucun package, vos classes atterrissent dans le package par défaut — convenable pour un extrait de code jetable, mais les classes qui s'y trouvent ne peuvent pas être importées par du code packageté, donc évitez-le dans les vrais projets.
Un exemple minimal
Supposons que vous vouliez un petit package utilitaire appelé com.w3docs.greet. Voici la structure :
project/
└── src/
└── com/
└── w3docs/
└── greet/
├── Greeter.java
├── Greeting.java
└── Main.javaGreeting.java :
package com.w3docs.greet;
public record Greeting(String language, String text) {}Greeter.java :
package com.w3docs.greet;
public class Greeter {
public Greeting greet(String name) {
return new Greeting("en", "Hello, " + name + "!");
}
}Main.java :
package com.w3docs.greet;
public class Main {
public static void main(String[] args) {
System.out.println(new Greeter().greet("Ada").text());
}
}Les trois fichiers commencent par la même ligne package com.w3docs.greet;. Parce qu'ils partagent un package, Greeter et Main peuvent utiliser Greeting sans import — vous n'importez que les types d'autres packages.
Compiler et exécuter depuis la ligne de commande
Depuis la racine project/, les commandes canoniques sont :
# Compile every .java file under src/ into a parallel tree under out/
javac -d out $(find src -name "*.java")
# Run a main class by its fully-qualified name, telling the JVM where out/ is.
java -cp out com.w3docs.greet.Main-d out indique à javac où placer les fichiers .class compilés ; il préserve la structure de répertoires du package. -cp out (classpath) indique à java comment les trouver à l'exécution — le prochain chapitre sur le Java classpath entre dans les détails.
Si la déclaration de package ne correspond pas à l'emplacement du fichier par rapport à la racine source, javac l'accepte (le package est ce qui est déclaré, non ce qui est déduit du chemin) — mais java échouera à l'exécution avec NoClassDefFoundError. Gardez toujours les deux en synchronisation.
Les sous-packages ne sont pas imbriqués
Il est tentant de penser que com.example « contient » com.example.util, mais pour le compilateur Java ce sont deux packages sans rapport qui partagent simplement un préfixe de nom. Une classe dans com.example n'a pas d'accès particulier aux membres package-private de com.example.util. Il n'existe pas d'héritage de package.
Ce que les sous-packages vous apportent, c'est une arborescence de répertoires facile à naviguer et un endroit logique pour regrouper du code lié. La plupart des vrais projets utilisent des sous-packages par fonctionnalité (auth, billing, parser) ou par couche (controller, service, repository) — mais aucun de ces choix ne confère au sous-package un accès supplémentaire.
Unités de compilation et package-info.java
Un fichier .java est aussi appelé une unité de compilation, et il peut contenir :
- Une déclaration
package(ou aucune, pour le package par défaut). - N'importe quel nombre de déclarations
import. - N'importe quel nombre de déclarations de types, dont au plus une peut être
public, et celle-là doit correspondre au nom du fichier.
Il existe aussi un fichier spécial nommé package-info.java dont le seul rôle est de porter la Javadoc et les annotations au niveau du package :
/**
* Greeting utilities for the W3Docs Java book.
*/
@NullMarked
package com.w3docs.greet;Pas de types — juste le commentaire, des annotations facultatives et la ligne package. Vous verrez cela dans les bibliothèques bien documentées.
Un exemple complet
Ce programme déclare deux types qui résideraient dans le même package dans un vrai projet et les utilise ensemble. Le widget exécutable aplatit la structure de fichiers pour que vous puissiez voir la mécanique dans une seule liste source, mais dans un vrai projet chaque type public résiderait dans son propre fichier .java sous la structure de répertoires présentée ci-dessus.
Et ensuite
Les packages personnalisés couvrent le code que vous écrivez vous-même. La plupart du temps, cependant, vous vous appuierez sur les packages du JDK — les classes de la bibliothèque standard pour les collections, les entrées/sorties, le temps, etc. Le prochain chapitre est une visite guidée de ceux que vous utiliserez le plus souvent. Continuez vers Java built-in packages.