Modificatori di accesso in Java
Controlla la visibilità in Java con i modificatori di accesso public, private, protected e package-private (default).
I modificatori di accesso stabiliscono chi può vedere e utilizzare una classe, un campo, un metodo o un costruttore. Java dispone di quattro livelli — public, protected, package-private (senza parola chiave) e private — che vanno da "tutto il mondo" a "solo questa classe." Scegliere quello giusto è il modo per delimitare l'interfaccia di un oggetto rispetto ai suoi dettagli interni.
I quattro livelli
Dal più permissivo al più restrittivo:
| Modificatore | Visibile da |
|---|---|
public | Ovunque |
protected | Stesso package, o qualsiasi sottoclasse (anche in un altro package) |
| (nessuna parola chiave) | Solo lo stesso package — package-private |
private | Solo la stessa classe |
Questo è tutto. Nessun "friend", nessun "module-internal" a questo livello; la visibilità dei moduli è una funzionalità separata del Java Platform Module System di cui di solito non hai bisogno.
public
Un membro public fa parte dell'API pubblicata della classe — visibile a qualsiasi codice che può vedere la classe stessa:
public class Greeter {
public String greet(String name) {
return "Hello, " + name;
}
}
new Greeter().greet("world"); // anyone can call thisUsa public per le cose che intendi far chiamare ad altro codice — anche ad altri progetti. Il costo è che una volta che qualcosa è pubblico, ti sei impegnato; cambiare la firma rompe ogni chiamante.
private
private limita un membro alla sua classe dichiarante. Niente all'esterno può toccarlo — nemmeno una sottoclasse:
public class Account {
private int balance; // only Account can read/write
public void deposit(int amount) {
if (amount <= 0) throw new IllegalArgumentException();
balance += amount; // ok — same class
}
}
Account a = new Account();
a.balance = -1; // ERROR — balance is privateQuesto è il cavallo di battaglia per i campi. Nascondere lo stato dietro private è ciò che dà un significato reale alla validazione in deposit. Il capitolo sull'incapsulamento approfondisce il pattern.
Package-private (senza parola chiave)
Ometti del tutto il modificatore e il membro sarà visibile a tutto ciò che si trova nello stesso package — ma non all'esterno:
// in package com.shop
class CartHelper { // no public — package-private
static int sum(int[] prices) { ... }
}Le altre classi in com.shop possono chiamare CartHelper.sum(...); il codice in com.app non può nemmeno vedere che la classe esiste. Usalo per gli helper interni che il package deve condividere ma che non fanno parte dell'API esterna del progetto.
Un errore comune: omettere il modificatore perché lo si è dimenticato, e poi sorprendersi quando la classe può essere usata da main (anch'essa nello stesso package durante l'apprendimento) ma non da un test in un package diverso.
protected
protected è package-private più le sottoclassi. Il codice nello stesso package può usare il membro, e qualsiasi sottoclasse — anche una in un package diverso — può usarlo:
public class Shape {
protected double area; // subclasses can read/write
}
public class Circle extends Shape {
Circle(double r) {
this.area = Math.PI * r * r; // ok — subclass access
}
}Questo è quello a cui ricorrere quando vuoi che le sottoclassi possano integrarsi con i meccanismi del genitore, ma non vuoi che il codice client generico lo tocchi. In pratica, protected compare molto meno spesso di public o private; molti progettisti preferiscono campi private con metodi accessor protected per lo stesso effetto con maggiore controllo.
Dove si applicano i modificatori
Puoi mettere un modificatore su:
- Una classe stessa (
public class Foo). Le classi top-level possono essere solopublico package-private. Le classi interne possono essere una qualsiasi dei quattro. - Un campo (
private int count). - Un metodo (
public int get() {...}). - Un costruttore (
private Singleton() {...}— vedi il singleton pattern).
Non puoi mettere un modificatore di accesso su una variabile locale o su un parametro di metodo. Questi hanno uno scope determinato esclusivamente dal punto in cui sono dichiarati.
La regola "una classe pubblica per file"
Un file .java può dichiarare più classi top-level, ma al massimo una di esse può essere public, e il nome di quella deve corrispondere al nome del file:
// file: Order.java
public class Order { ... } // ok — matches filename
class OrderHelper { ... } // ok — package-private
public class Customer { ... } // ERROR — second public classLa maggior parte dei progetti mantiene una classe per file comunque, ma gli helper package-private accanto a una classe pubblica sono a volte utili.
Scegliere quello giusto
Una regola pratica che si adatta bene:
- Prediligi
privateper i campi e i metodi helper. publicper i metodi che vuoi effettivamente vengano chiamati dall'esterno.- Package-private per le cose che devono essere condivise all'interno di un package ma non esposte oltre.
protectedsolo quando vuoi specificamente anche l'accesso dalle sottoclassi.
È facile allargare l'accesso in seguito (private → public); è doloroso restringerlo senza rompere i chiamanti. Inizia stretto.
I modificatori non cambiano il comportamento
Un modificatore di accesso è un controllo in fase di compilazione. A runtime, due campi int uguali si comportano in modo identico che siano stati dichiarati public o private. Il modificatore esiste esclusivamente per impedire ad altro codice di compilare contro il membro — per imporre un confine che stai dichiarando.
Un esempio pratico
Cosa c'è dopo
public, protected, private sono modificatori di accesso. Java ha un'altra famiglia — i modificatori non di accesso come static, final, abstract, synchronized — che controllano il comportamento piuttosto che la visibilità. Il prossimo capitolo, modificatori non di accesso, è una panoramica di questi.