Modificateurs d'accès en Java - public, private, protected et package

03 Sep 2019 03 Sep 2019 16254 vues ESSADDOUKI Mostafa 12 min de lecture
Introduction
1 Nouveautés de Java 11 2 Différences entre JDK, JRE et JVM 3 Structure d'un programme Java - Hello World 4 Mots clés et conventions de dénomination en Java 5 Types de données intégrés en Java 6 Les variables en Java 7 Classes enveloppe - Number, Integer, Double ... 8 Lire les entrées clavier en Java
Structures de contrôle
9 Les opérateurs en Java 10 Les structures conditionnelles en Java 11 Les boucles en Java 12 Instructions de contrôle de boucle - break, continue
Chaines de caractères
13 Les chaines en Java - API String 14 Les chaines en Java - StringBuffer et StringBuilder 15 Les expressions régulières en Java
Programmation OO
16 Objets et classes en Java 17 Modificateurs d'accès Java - public, private, protected et package 18 Méthodes et surcharge des méthodes en Java 19 les constructeurs en Java 20 L'héritage en Java 21 Classes abstraites en Java 22 Interfaces et héritage multiple en Java 23 Les classes imbriquées en Java 24 Les singletons en Java 25 Classes et méthodes génériques 26 Interface fonctionnelle et expressions Lambda en Java
Tableaux et collections
27 Les tableaux en Java 28 Classe Arrays - java.util.Arrays 29 Les listes dynamiques - java.util.ArrayList 30 Les listes chaînées en Java - java.util.LinkedList 31 HashSet en Java - java.util.HashSet 32 HashMap en Java - java.util.HashMap
Gestion des fichiers
33 Comprendre les fichiers informatiques 34 Utilisation des classes Path et Files en Java 35 Lecture et écriture dans un fichier en Java 36 Fichiers à accès aléatoire en Java
Gestion d'exceptions
37 Gestion d'exceptions en Java 38 Créez vos propres classes d'exception en Java
Programmation concurrente
39 Introduction à la programmation concurrente en Java - Multi-threads 40 classe java.lang.Thread 41 Synchronisation des threads en Java
Cours Java pour les débutants — Étape 17 sur 41

Modificateurs d'accès en Java

  Prérequis

Maîtriser la notion de classe, d'objet et de méthode en Java. Comprendre les concepts de package et d'héritage (notion de base). Connaître les mots-clés public, private vus dans les cours précédents.

  Objectifs

Comprendre les quatre niveaux de visibilité en Java (private, package, protected, public). Maîtriser le principe d'encapsulation via les getters/setters. Savoir choisir le modificateur adapté à chaque membre d'une classe.

1. Qu'est-ce qu'un modificateur ?

Définition — Modificateur Un modificateur est un mot-clé ajouté à la définition d'une classe, d'un attribut, d'une méthode ou d'un constructeur pour en changer le comportement ou la visibilité. Java distingue deux grandes catégories :
  • Modificateurs d'accès : contrôlent la visibilité depuis d'autres classes.
  • Modificateurs sans accès : modifient d'autres propriétés (static, final, abstract…).

Ce cours se concentre sur les modificateurs d'accès, qui sont au cœur du principe d'encapsulation.

2. Les quatre niveaux d'accès

Modificateur Même classe Même package Sous-classe Partout
private Oui Non Non Non
(aucun — package) Oui Oui Non Non
protected Oui Oui Oui Non
public Oui Oui Oui Oui
Règle d'or de l'encapsulation Appliquez le principe du moindre privilège : accordez le niveau d'accès le plus restrictif possible. En pratique : attributs private, méthodes utilitaires internes private, API publique public.

3. Accès par défaut — package-private

Accès par défaut (package-private) Quand aucun modificateur d'accès n'est spécifié, le membre est accessible à toutes les classes du même package, mais invisible depuis d'autres packages. C'est parfois appelé accès package-private ou friendly.

  Exemple 1 — Membres sans modificateur

package ma.um6p.cpge;

public class CompteurPackage {

    int valeur;          // package-private — accessible dans le même package
    String description;  // package-private

    void incrementer() { // package-private
        valeur++;
    }
}
package ma.um6p.cpge; // même package : accès autorisé

class UtilisateurCompteur {
    public static void main(String[] args) {
        CompteurPackage c = new CompteurPackage();
        c.valeur = 10;      // accessible (même package)
        c.incrementer();    // accessible (même package)
        System.out.println(c.valeur); // 11
    }
}
Accès refusé depuis un autre package
package ma.um6p.autre; // package différent
import ma.um6p.cpge.CompteurPackage;

class Test {
    public static void main(String[] args) {
        CompteurPackage c = new CompteurPackage();
        c.valeur = 5; // Erreur de compilation : valeur has package access
    }
}

4. Modificateur private

private — accès le plus restrictif Un membre déclaré private n'est accessible que depuis l'intérieur de la classe où il est défini. Il est invisible depuis toute autre classe, même dans le même package. private est le fondement de l'encapsulation.
Règle — private et classes Une classe de niveau supérieur ne peut pas être private (elle serait inutilisable). Seuls les membres (attributs, méthodes, constructeurs) et les classes internes peuvent être private.

4.1 Encapsulation avec getters et setters

Les attributs private sont exposés de manière contrôlée via des méthodes publiques d'accès (getters) et de modification (setters).

   
Convention getter / setter Java
// Getter — lire la valeur
public TypeAttribut getNomAttribut() {
    return nomAttribut;
}

// Setter — modifier la valeur
public void setNomAttribut(TypeAttribut valeur) {
    this.nomAttribut = valeur;
}

  Exemple 2 — Classe Personne avec attributs privés

public class Personne {

    // Attributs privés — invisibles de l'extérieur
    private String nom;
    private int    age;

    // Constructeur
    public Personne(String nom, int age) {
        this.nom = nom;
        setAge(age); // on utilise le setter pour bénéficier de la validation
    }

    // Getter — lecture du nom
    public String getNom() {
        return nom;
    }

    // Setter — modification du nom
    public void setNom(String nom) {
        if (nom != null && !nom.isBlank()) {
            this.nom = nom;
        }
    }

    // Getter — lecture de l'âge
    public int getAge() {
        return age;
    }

    // Setter avec validation — modification de l'âge
    public void setAge(int age) {
        if (age >= 0 && age <= 150) {
            this.age = age;
        } else {
            System.out.println("Âge invalide : " + age);
        }
    }

    public static void main(String[] args) {
        Personne p = new Personne("Mostafa", 30);
        System.out.println(p.getNom() + " a " + p.getAge() + " ans");

        p.setAge(-5);  // refusé par la validation
        p.setAge(31);  // accepté
        System.out.println("Nouvel âge : " + p.getAge());

        // p.age = 25; // Erreur de compilation — private !
    }
}
Sortie
Mostafa a 30 ans
Âge invalide : -5
Nouvel âge : 31
Avantage du setter avec validation En passant par un setter, on peut valider la valeur avant de l'affecter. Un accès direct à l'attribut (p.age = -5) ne permettrait aucun contrôle. C'est l'un des principaux bénéfices de l'encapsulation.

5. Modificateur public

public — accès le plus permissif Un membre déclaré public est accessible depuis n'importe quelle classe, quel que soit le package. Si la classe elle-même se trouve dans un autre package, elle doit être importée, mais l'accès à ses membres public est alors autorisé.

  Exemple 3 — Membres publics

public class Calculatrice {

    // Méthode publique — accessible partout
    public double additionner(double a, double b) {
        return a + b;
    }

    public double diviser(double a, double b) {
        if (b == 0) {
            afficherErreur("Division par zéro !"); // appel d'une méthode privée
            return 0;
        }
        return a / b;
    }

    // Méthode privée — détail d'implémentation interne
    private void afficherErreur(String msg) {
        System.err.println("Erreur : " + msg);
    }
}
// Depuis une autre classe ou package
Calculatrice calc = new Calculatrice();
System.out.println(calc.additionner(3, 4)); // 7.0 — public : accessible
// calc.afficherErreur("test");             // Erreur — private : inaccessible
main() doit être public La méthode main() doit obligatoirement être déclarée public pour que la JVM puisse l'appeler depuis l'extérieur de la classe lors du lancement du programme.
public static void main(String[] args) { ... }

6. Modificateur protected

protected — accès package + sous-classes Un membre protected est accessible :
  • depuis toutes les classes du même package,
  • depuis toutes les sous-classes (même dans un autre package via héritage).
Il est typiquement utilisé pour partager une fonctionnalité avec les sous-classes tout en la cachant aux classes non liées.

  Exemple 4 — protected entre packages via héritage

// Package p1
package p1;

public class Animal {

    protected String nom;

    // Méthode protected — accessible par les sous-classes
    protected void seDeplacer() {
        System.out.println(nom + " se déplace.");
    }

    // Méthode private — inaccessible même aux sous-classes
    private void respirer() {
        System.out.println("Respiration interne.");
    }
}
// Package p2 — autre package
package p2;
import p1.Animal;

public class Chien extends Animal {

    public Chien(String nom) {
        this.nom = nom; // nom est protected → accessible dans la sous-classe
    }

    public void aboyer() {
        System.out.println(nom + " aboie !");
        seDeplacer(); // protected → accessible dans la sous-classe
        // respirer(); // Erreur — private → inaccessible
    }

    public static void main(String[] args) {
        Chien c = new Chien("Rex");
        c.aboyer();
    }
}
Sortie
Rex aboie !
Rex se déplace.

6.1 Règles d'héritage et modificateurs d'accès

Règles de redéfinition (override) et visibilité Lors de la redéfinition d'une méthode dans une sous-classe, la visibilité ne peut être que maintenue ou élargie — jamais restreinte :
  • Une méthode public redéfinie doit rester public.
  • Une méthode protected redéfinie peut devenir protected ou public.
  • Une méthode private n'est pas héritée — elle n'est donc pas redéfinissable.
class Base {
    public    void methodePublique()   { }
    protected void methodeProtegee()  { }
    private   void methodePrivee()    { }
}

class Derivee extends Base {
    public    void methodePublique()   { } // maintenu public
    public    void methodeProtegee()  { } // élargi : protected → public (autorisé)
    // protected void methodePublique() { } // Erreur : restreint de public à protected
}

7. Comparaison complète et guide de choix

Situation Modificateur recommandé Raison
Attribut de classe private Encapsulation — accès uniquement via getters/setters
Méthode de l'API publique public Accessible aux utilisateurs de la classe
Méthode utilitaire interne private Détail d'implémentation, non exposé
Méthode partagée avec sous-classes protected Accessible en héritage, cachée ailleurs
Classe utilitaire dans un package (aucun — package-private) Visible dans le package, cachée à l'extérieur
Constante partagée (static final) public static final Constante globale accessible partout

8. Exercice

Concevoir une classe CompteBancaire encapsulée

Niveau : Intermédiaire

Concevoir une hiérarchie de classes bancaires en appliquant les bons modificateurs d'accès à chaque membre.

Travail demandé

  1. Créer une classe Compte avec :
    • private double solde — solde du compte
    • private String numeroCpte — numéro de compte
    • protected String titulaire — accessible aux sous-classes
    • Un constructeur public initialisant les trois attributs
    • Un getter public getSolde() et un getter public getNumeroCpte()
    • Une méthode protected crediter(double montant) — accessible aux sous-classes
    • Une méthode private validerMontant(double montant) — vérification interne
  2. Créer une sous-classe CompteCourant extends Compte avec :
    • Un attribut private double decouvertMax
    • Une méthode public debiter(double montant) qui autorise le découvert jusqu'à decouvertMax
  3. Tester dans un main en créant un CompteCourant et en simulant des opérations.
Sortie attendue
Sortie
Compte de Mostafa — N°FR001 — Solde : 1000.0 $
Crédit de 500.0 $. Nouveau solde : 1500.0 $
Débit de 1800.0 $. Nouveau solde : -300.0 $
Découvert maximal atteint — débit refusé.
Solde final : -300.0 $
Contraintes
  • Les attributs de Compte doivent être private ou protected selon le besoin
  • validerMontant doit être private
  • crediter doit être protected
  • Aucun accès direct à solde depuis CompteCourant

  L'essentiel en bref

Java propose quatre niveaux de visibilité. private est le plus restrictif : accessible uniquement dans la classe elle-même — c'est le fondement de l'encapsulation. L'accès package-private (aucun mot-clé) limite la visibilité au package courant. protected étend cet accès aux sous-classes, même dans d'autres packages, ce qui est utile pour l'héritage. public est le plus permissif et rend le membre accessible partout. En pratique : déclarez les attributs private, exposez-les via des getters/setters public avec validation, et utilisez protected pour partager des comportements avec les sous-classes. Lors de la redéfinition d'une méthode, la visibilité ne peut jamais être restreinte.

Sortie
// La sortie apparaîtra ici…
Prêt · Ctrl+Entrée pour exécuter

Discussion (0)

Soyez le premier à laisser un commentaire !

Laisser un commentaire

Votre commentaire sera visible après modération.