Aller au contenu principal

Modificateurs d'accès et visibilité

En Java, les modificateurs d'accès sont des mots-clés qui définissent l'accessibilité (visibilité) des classes, des constructeurs, des méthodes et des champs. Ils constituent un aspect fondamental de l'encapsulation, un principe de programmation orientée objet qui permet de masquer les détails d'implémentation internes et de contrôler la manière dont d'autres parties du code peuvent interagir avec vos classes et leurs membres.

Il existe quatre types de modificateurs d'accès en Java :

  1. public
  2. protected
  3. default (ou paquet-privé)
  4. private

Ces modificateurs spécifient qui peut accéder à un membre : la classe elle-même, d'autres classes du même paquet, les sous-classes (même dans des paquets différents), ou toutes les classes.


1. public

Le modificateur d'accès public est le plus permissif. Lorsqu'une classe, une méthode ou un champ est déclaré public, cela signifie qu'il est accessible de n'importe où dans l'application.

  • Classes : Une classe public peut être accédée par n'importe quelle autre classe.
  • Méthodes/Champs/Constructeurs : Les membres public peuvent être accédés depuis n'importe quelle classe, quel que soit le paquet.

Visibilité : Accessible partout.

Exemple :

// package com.example.model
package com.example.model;

public class PublicClass { // Classe publique
public int publicField = 10; // Champ public

public PublicClass() { // Constructeur public
System.out.println("PublicClass constructor called.");
}

public void publicMethod() { // Méthode publique
System.out.println("This is a public method.");
}
}

// package com.example.app
package com.example.app;

import com.example.model.PublicClass;

public class AccessPublic {
public static void main(String[] args) {
PublicClass obj = new PublicClass(); // Accessible
System.out.println(obj.publicField); // Accessible
obj.publicMethod(); // Accessible
}
}

2. protected

Le modificateur d'accès protected permet d'accéder aux membres depuis :

  1. La même classe.
  2. Les classes du même paquet.
  3. Les sous-classes (classes enfants) dans n'importe quel paquet.

Il est principalement utilisé lorsque vous souhaitez autoriser les sous-classes à accéder à un membre, tout en empêchant les classes non apparentées de le faire.

Visibilité :

  • Au sein de la même classe.
  • Au sein du même paquet.
  • Par les sous-classes (même si elles se trouvent dans un paquet différent).

Exemple :

// package com.example.model
package com.example.model;

public class Vehicle {
protected String type = "Generic Vehicle";

protected void startEngine() {
System.out.println("Engine started for " + type);
}
}

// package com.example.model (même paquet)
package com.example.model;

class Garage {
public void testVehicle() {
Vehicle car = new Vehicle();
car.startEngine(); // Accessible, même paquet
System.out.println(car.type); // Accessible, même paquet
}
}

// package com.example.app (paquet différent, sous-classe)
package com.example.app;

import com.example.model.Vehicle; // Import nécessaire pour l'héritage

public class Car extends Vehicle { // Car est une sous-classe de Vehicle
public Car() {
this.type = "Car"; // Accessible, car Car est une sous-classe
}

public void drive() {
startEngine(); // Accessible, car Car est une sous-classe
System.out.println(type + " is driving.");
}

public static void main(String[] args) {
Car myCar = new Car();
myCar.drive(); // Sortie : Engine started for Car, Car is driving.
}
}

// package com.example.app (paquet différent, PAS une sous-classe)
package com.example.app;

// import com.example.model.Vehicle; // Décommenter si nécessaire

public class Mechanic {
public static void main(String[] args) {
// Vehicle someVehicle = new Vehicle(); // Pourrait nécessiter un import
// someVehicle.startEngine(); // ERREUR DE COMPILATION : Impossible d'accéder au membre protected en dehors du paquet, sauf si c'est une sous-classe
// System.out.println(someVehicle.type); // ERREUR DE COMPILATION
}
}

3. default (Paquet-privé)

Lorsqu'aucun modificateur d'accès n'est explicitement spécifié pour une classe, une méthode ou un champ, il reçoit le niveau d'accès default. C'est également connu sous le nom d'accès "paquet-privé".

Les membres default sont accessibles uniquement depuis :

  1. La même classe.
  2. D'autres classes au sein du même paquet.

Ils ne sont pas accessibles par les sous-classes dans des paquets différents.

Visibilité :

  • Au sein de la même classe.
  • Au sein du même paquet.

Exemple :

// package com.example.data
package com.example.data;

class UserProfile { // Classe avec accès par défaut (accessible uniquement dans com.example.data)
String userName = "Guest"; // Champ avec accès par défaut

void displayProfile() { // Méthode avec accès par défaut
System.out.println("User: " + userName);
}
}

// package com.example.data (même paquet)
package com.example.data;

public class ProfileManager {
public void showUserProfile() {
UserProfile user = new UserProfile(); // Accessible (même paquet)
System.out.println("Manager accessing: " + user.userName); // Accessible
user.displayProfile(); // Accessible
}
}

// package com.example.app (paquet différent)
package com.example.app;

// import com.example.data.UserProfile; // ERREUR DE COMPILATION : UserProfile n'est pas public dans com.example.data ; ne peut pas être accédé depuis l'extérieur du paquet

public class MainApp {
public static void main(String[] args) {
// UserProfile user = new UserProfile(); // ERREUR DE COMPILATION (UserProfile a un accès par défaut)
// new com.example.data.UserProfile(); // ERREUR DE COMPILATION (même avec le nom entièrement qualifié)

// Cependant, si ProfileManager (public) expose UserProfile, c'est acceptable pour les membres publics
// ProfileManager manager = new ProfileManager();
// manager.showUserProfile(); // Cela fonctionnerait si ProfileManager était importé et public
}
}

4. private

Le modificateur d'accès private est le plus restrictif. Les membres private (champs, méthodes, constructeurs) ne sont accessibles qu'à partir de la même classe dans laquelle ils sont déclarés.

  • Les classes private ne sont pas directement prises en charge (sauf pour les classes imbriquées).
  • private est fondamental pour l'encapsulation, permettant aux classes de masquer leur état interne et les détails d'implémentation au monde extérieur.

Visibilité : Accessible uniquement au sein de la même classe.

Exemple :

// package com.example.core
package com.example.core;

public class BankAccount {
private double balance; // Champ privé

public BankAccount(double initialBalance) { // Constructeur public pour l'accès externe
this.balance = initialBalance;
}

private void logTransaction(String message) { // Méthode privée
System.out.println("Transaction Log: " + message);
}

public void deposit(double amount) { // Méthode publique pour interagir avec le solde
if (amount > 0) {
this.balance += amount;
logTransaction("Deposited " + amount + ". New balance: " + balance); // Accessible au sein de la classe
}
}

public double getBalance() { // Getter public
return balance;
}
}

// package com.example.app
package com.example.app;

import com.example.core.BankAccount;

public class BankingApp {
public static void main(String[] args) {
BankAccount myAccount = new BankAccount(1000.0);
myAccount.deposit(500.0); // Accessible

System.out.println("Current balance: " + myAccount.getBalance()); // Accessible

// myAccount.balance = 2000.0; // ERREUR DE COMPILATION : balance a un accès privé
// myAccount.logTransaction("Unauthorized access"); // ERREUR DE COMPILATION : logTransaction a un accès privé
}
}

Tableau récapitulatif

ModificateurMême ClasseMême PaquetSous-classe (paquet différent)Partout (paquet différent, pas une sous-classe)
privateOuiNonNonNon
defaultOuiOuiNonNon
protectedOuiOuiOuiNon
publicOuiOuiOuiOui

Points clés à retenir

  • Encapsulation : Les modificateurs d'accès sont cruciaux pour faire respecter l'encapsulation. Ils vous permettent de masquer le fonctionnement interne d'une classe, n'exposant que ce qui est nécessaire, ce qui rend le code plus maintenable et moins sujet aux erreurs.
  • Conception d'API : Lors de la conception d'API, vous exposez généralement des méthodes et des classes public qui définissent le contrat public de votre composant, tout en gardant l'état interne et les méthodes d'aide private ou protected.
  • Flexibilité vs. Contrôle : Chaque modificateur offre un équilibre différent entre la flexibilité (l'étendue de l'accessibilité d'un membre) et le contrôle (la mesure dans laquelle vous restreignez son utilisation).
  • Accès au niveau des classes : Les classes de niveau supérieur ne peuvent être que public ou default. Les classes internes/imbriquées peuvent utiliser les quatre modificateurs d'accès.