W3docs

Les packages Java

Regroupez les classes Java en packages, respectez les conventions de nommage et structurez vos projets pour une meilleure maintenabilité.

Java n'utilise pas un seul grand espace de noms pour toutes les classes. Chaque classe vit dans un package — un espace nommé qui sert à la fois d'unité d'organisation et d'espace de noms Java. Deux classes appelées Logger peuvent coexister sans collision tant qu'elles se trouvent dans des packages différents, et le nom du package est présent partout : dans les instructions import, dans les noms pleinement qualifiés, dans le système de fichiers, et même dans les manifestes JAR. Connaître les packages est ce qui vous permet de comprendre la structure d'un projet en un coup d'œil.

Cette page explique ce qu'est un package, comment le nommer, le cas particulier du package par défaut, la correspondance entre noms de packages et répertoires, et comment déclarer un package dans votre propre fichier source.

Ce qu'est réellement un package

Un package remplit trois fonctions à la fois :

  • Un espace de noms. java.util.Date et java.sql.Date sont des classes différentes ; le nom du package les distingue.
  • Une frontière d'accès. Sans modificateur, les membres ne sont visibles qu'au sein du même package — le niveau d'accès « package-private ». Il s'agit d'une forme structurelle réelle d'encapsulation ; voir Modificateurs d'accès.
  • Un répertoire. Le nom du package correspond directement à un chemin de dossier. com.example.app.util se trouve à com/example/app/util/.

Le même nom est utilisé à trois endroits — la déclaration, le chemin du fichier et l'import — et ils doivent tous concorder.

Conventions de nommage

La convention Java est le nommage en DNS inversé, basé sur un domaine que vous contrôlez :

  • Tout en minuscules : com.example, et non Com.Example.
  • Ordre de domaine inversé : un projet sur w3docs.com utilise com.w3docs comme racine.
  • Les segments de projet, module et fonctionnalité suivent : com.w3docs.learnjava.parser.
  • Évitez les mots réservés Java comme segments (int, class, new). Si votre domaine en contient un, modifiez-le : com.example.int_ ou découpez-le différemment.

Ces conventions ont de l'importance au-delà de l'esthétique. La règle du DNS inversé est ce qui permet de placer des JAR de différentes organisations dans le même classpath sans conflits de noms.

Le package par défaut

Un fichier .java sans déclaration package appartient au package par défaut (sans nom). Deux conséquences en découlent :

  • Vous ne pouvez pas utiliser import depuis le package par défaut vers un package nommé. Tout ce qui s'y trouve est effectivement inaccessible depuis du vrai code.
  • Les outils de build, les IDE et les systèmes de modules traitent tous le package par défaut comme un cas dégénéré — beaucoup refusent carrément de compiler contre lui.

Utilisez-le pour des fichiers Hello.java ponctuels. Ne le livrez pas en production.

Correspondance entre packages et répertoires

Si vous déclarez package com.w3docs.learnjava.parser; en haut de Tokenizer.java, le fichier doit se trouver à :

com/w3docs/learnjava/parser/Tokenizer.java

par rapport à la racine des sources. Le compilateur n'infère pas le package à partir du chemin — il lit la déclaration, puis vous fait confiance. Mais l'environnement d'exécution (et la plupart des outils) ne seront pas satisfaits si les deux ne correspondent pas.

Cette racine des sources est là où commence le labyrinthe du classpath : la JVM doit savoir où commence l'arborescence des packages, sinon elle ne peut rien trouver.

Déclarer un package

L'instruction package est ce qui assigne une classe à un package. Elle doit être la toute première instruction du fichier — avant tout import, avant la classe elle-même. Seuls les commentaires et les lignes vides peuvent la précéder.

// File: com/w3docs/learnjava/parser/Tokenizer.java
package com.w3docs.learnjava.parser;

import java.util.List;

public class Tokenizer {
    public List<String> tokenize(String source) {
        // ...
        return List.of();
    }
}

Depuis n'importe quel autre endroit, cette classe est désormais connue par son nom pleinement qualifié, com.w3docs.learnjava.parser.Tokenizer. Le code du même package peut y faire référence simplement avec Tokenizer ; le code d'autres packages doit soit l'importer, soit épeler le nom complet.

Avertissement
Un fichier peut contenir au plus une instruction package, et une seule classe public de premier niveau — dont le nom doit correspondre au nom du fichier. Placez package ailleurs qu'en tête de fichier et le compilateur rejettera le fichier.

Un exemple concret : deux Logger

L'argument le plus clair en faveur des packages est la collision qu'ils évitent. Le programme suivant utilise deux classes appelées Logger en esprit — le java.util.logging.Logger du JDK par son nom pleinement qualifié — et montre comment le package d'une classe fait partie de son identité à l'exécution.

java— editable, runs on the server

Deux enseignements à tirer de son exécution : les classes connaissent leur propre package à l'exécution (via Class.getName() et Class.getPackage()), et le nom pleinement qualifié est ce qui identifie un type sans ambiguïté — Logger seul est ambigu ; java.util.logging.Logger ne l'est pas.

Prochaine étape

Nommer un package est une chose ; importer ses types dans votre propre code en est une autre. Le chapitre suivant couvre l'instruction import — les imports de type unique, les imports avec wildcard, les imports statiques, et quand chacun est le bon choix.

Exercice

Pratique
Pourquoi la convention standard de Java pour les noms de packages utilise-t-elle l'ordre de domaine inversé, comme `com.example.app` ?
Pourquoi la convention standard de Java pour les noms de packages utilise-t-elle l'ordre de domaine inversé, comme `com.example.app` ?
Was this page helpful?