Les 3 visibilités
Les modificateurs d'accès
Notions théoriques
Pourquoi contrôler la visibilité ?
Les modificateurs d'accès permettent de contrôler quelles parties du code peuvent accéder aux attributs et méthodes d'une classe. C'est le fondement de l'encapsulation : on cache ce qui est interne, on expose ce qui est nécessaire.
Les 4 niveaux de visibilité en Java
| Modificateur | Accessible depuis... |
|---|---|
public | Partout (toutes les classes, tous les packages) |
protected | La même classe + les sous-classes + le même package |
| (rien) package-private | La même classe + le même package uniquement |
private | La même classe uniquement |
Java a en réalité 4 niveaux de visibilité, mais on en retient souvent 3 : public, protected, private. La visibilité "package-private" (sans mot-clé) est moins souvent utilisée explicitement.
public : accessible partout
public class Personnage {
public String nom; // lisible et modifiable depuis n'importe où
public int force;
}
Utilisez public pour les méthodes que d'autres classes doivent appeler. Pour les attributs, préférez private (voir section suivante).
private : accessible seulement dans la classe
public class Personnage {
private String nom; // non accessible depuis l'extérieur
private int force;
private int pointsDeVie;
}
Depuis une autre classe :
Personnage p = new Personnage("Aria", 15, 100);
System.out.println(p.nom); // ERREUR de compilation !
p.force = 20; // ERREUR de compilation !
protected : accessible dans la hiérarchie et le package
protected est surtout utile pour l'héritage (séance suivante) : les sous-classes peuvent accéder aux attributs protected de leur classe parente.
public class Personnage {
protected String nom; // accessible dans les sous-classes
protected int force;
private int pointsDeVie; // non accessible même dans les sous-classes
}
public class Guerrier extends Personnage {
void afficherNom() {
System.out.println(nom); // OK : protected accessible dans sous-classe
}
}
Package-private (sans modificateur)
Sans aucun modificateur, un membre est accessible dans toutes les classes du même package, mais pas depuis les packages extérieurs.
public class Personnage {
String nom; // package-private : accessible dans com.joliciel.rpg.personnages
int force; // mais pas depuis com.joliciel.rpg.combat
}
La règle d'or
Les attributs sont
private, les méthodes publiquement utiles sontpublic.
C'est la règle de base de l'encapsulation. On protège les données, on expose les services.
public class Personnage {
private String nom; // attributs private
private int force;
private int pointsDeVie;
public String getNom() { return nom; } // méthodes public pour accéder
public int getForce() { return force; }
public void soigner(int pts) { pointsDeVie += pts; } // méthode métier public
}
Tableau comparatif
| Même classe | Même package | Sous-classe | Partout | |
|---|---|---|---|---|
private | Oui | Non | Non | Non |
| (package-private) | Oui | Oui | Non | Non |
protected | Oui | Oui | Oui | Non |
public | Oui | Oui | Oui | Oui |
Exemple pratique
// Fichier : Personnage.java
package com.joliciel.rpg.personnages;
public class Personnage {
private String nom;
private int force;
protected int defense; // accessible dans les sous-classes
private int pointsDeVie;
private static final int PV_MAX = 200; // constante privée
public Personnage(String nom, int force, int defense, int pointsDeVie) {
this.nom = nom;
this.force = force;
this.defense = defense;
this.pointsDeVie = pointsDeVie;
}
// Méthodes publiques : interface de la classe
public String getNom() { return nom; }
public int getForce() { return force; }
public int getPointsDeVie() { return pointsDeVie; }
public void recevoirDegats(int degats) {
int degatsEffectifs = calculerDegatsEffectifs(degats);
pointsDeVie -= degatsEffectifs;
System.out.println(nom + " perd " + degatsEffectifs + " PV.");
}
public boolean estVivant() {
return pointsDeVie > 0;
}
// Méthode privée : détail d'implémentation interne
private int calculerDegatsEffectifs(int degats) {
return Math.max(0, degats - defense);
}
public void afficher() {
System.out.println(nom + " : PV=" + pointsDeVie + "/" + PV_MAX);
}
}
// Fichier : Main.java
package com.joliciel.rpg;
import com.joliciel.rpg.personnages.Personnage;
public class Main {
public static void main(String[] args) {
Personnage hero = new Personnage("Aria", 18, 10, 100);
// Accès aux méthodes publiques : OK
System.out.println(hero.getNom());
hero.recevoirDegats(15);
// Accès direct aux attributs privés : IMPOSSIBLE
// hero.nom = "test"; // ERREUR DE COMPILATION
// hero.force = 99; // ERREUR DE COMPILATION
}
}
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Vous allez appliquer les bonnes visibilités à la classe Personnage.
Étape 1 — Rendre les attributs private
Transformez tous les attributs de Personnage en private.
Ne jamais laisser d'attributs sans modificateur ou avec public dans une classe de production. Des attributs private garantissent que les données ne peuvent être modifiées que de la façon prévue par la classe (via ses méthodes). C'est la base de l'encapsulation.
Étape 2 — Ajouter un getter public
Ajoutez une méthode public getNom() qui retourne la valeur de l'attribut private nom.
Créez des getters pour lire les attributs privés. En revanche, pour modifier un attribut, préférez des méthodes métier (soigner(), recevoirDegats()) plutôt que des setters génériques (setPointsDeVie()). Les méthodes métier peuvent valider et contrôler la modification.
Étape 3 — Extraire une méthode privée
Extrayez le calcul des dégâts effectifs dans une méthode private appelée depuis recevoirDegats().
Extrayez la logique complexe dans des méthodes private. Cela rend le code plus lisible (recevoirDegats appelle calculerDegatsEffectifs) et permet de modifier l'implémentation interne sans changer l'interface publique. Si la formule de calcul des dégâts change, seule la méthode private est à modifier.