1. Introduzione
In Java, come nella vita, non tutto deve essere accessibile a tutti e sempre. Immagina un appartamento: non vuoi che i vicini passeggino nella tua camera da letto, giusto? Allo stesso modo, nei programmi a volte vogliamo “chiudere la porta” a certe variabili o metodi, in modo che non siano accessibili dall’esterno.
Per questo in Java esistono i modificatori di accesso — parole speciali che indicano dove è possibile utilizzare una determinata variabile o un metodo: per esempio, public o private.
Modificatori di accesso principali
| Modificatore | Dove è visibile? |
|---|---|
|
Ovunque sia visibile la classe (anche in altri pacchetti e in altri file) |
|
Solo all’interno della stessa classe |
|
Solo all’interno dello stesso pacchetto (cioè all’interno delle classi nella stessa directory) |
Esistono anche altri modificatori, ma ne parleremo più avanti, quando arriveremo all’ereditarietà.
Esempio pratico
public class User
{
public String name; // visibile a tutti
private int age; // visibile solo all'interno della classe User
public void sayHello()
{
System.out.println("Ciao, mi chiamo " + name);
}
private void secretMethod()
{
System.out.println("È un metodo segreto!");
}
}
Spiegazione:
- name — visibile ovunque si possa usare la classe User.
- age — visibile solo all’interno della classe User.
- sayHello() — metodo pubblico, può essere chiamato da qualsiasi altra classe.
- secretMethod() — metodo privato, non può essere invocato dall’esterno.
Come funziona nei casi reali?
Supponiamo di avere una classe che descrive un conto bancario. Non vogliamo certo che chiunque possa modificare direttamente il saldo! Perciò la variabile del saldo sarà private, e per lavorarci useremo metodi dedicati.
Perché non conviene rendere tutto public?
Potrebbe venirti la tentazione: “Rendiamo tutto public, così non ci complichiamo la vita!” Ma è la via verso il caos. Immagina che chiunque possa modificare il tuo saldo, il nome utente o addirittura chiamare un metodo pensato solo per uso interno. Nei programmi di grandi dimensioni questo porta a errori e bug “magici”.
La regola d’oro dello sviluppatore Java:
Inizia rendendo tutto private, poi esponi verso l’esterno solo ciò che serve davvero.
2. Ambito di visibilità delle variabili
L’ambito di visibilità è la zona di codice in cui una variabile “esiste” e può essere utilizzata. Se esci da questa zona, la variabile “scompare” — come se non fosse mai esistita.
In Java esistono diversi tipi di variabili per ambito di visibilità:
- Variabili locali — dichiarate all’interno di un metodo o di un blocco di codice { ... }.
- Parametri del metodo — dichiarati tra le parentesi tonde del metodo.
- Campi della classe — dichiarati all’interno della classe ma fuori dai metodi.
Se una variabile è dichiarata all'interno di { blocco },
è visibile solo all'interno di quel blocco
e non è accessibile al di fuori di esso.
Variabili locali
Una variabile locale vive solo all’interno del metodo o del blocco in cui è dichiarata.
void printSum(int a, int b)
{
int sum = a + b; // variabile locale
System.out.println(sum);
}
// qui sum non esiste più!
Il tentativo di accedere a sum fuori dal metodo causerà un errore di compilazione: “Impossibile trovare la variabile sum”.
Parametri del metodo
Anche i parametri sono variabili, ma vivono solo all’interno del metodo.
void greet(String name)
{
System.out.println("Ciao, " + name);
}
// qui name non esiste più!
Campi della classe (variabili membro)
I campi della classe sono dichiarati all’interno della classe ma fuori dai metodi. Sono visibili in tutti i metodi della classe.
public class Counter
{
private int count = 0; // campo della classe
public void increment()
{
count++; // possiamo usare il campo
}
public int getCount()
{
return count; // possiamo usare il campo anche qui
}
}
3. Occultamento delle variabili (shadowing)
Occultamento (shadowing) — è la situazione in cui, in un certo ambito di visibilità, viene dichiarata una variabile (o un parametro) con lo stesso nome di una variabile in un ambito esterno. All’interno di quel blocco il “nuovo” nome oscura il precedente, e non è più possibile accedere direttamente al valore esterno.
Esempio di occultamento:
class ShadowDemo
{
int value = 10; // campo della classe
void printValue()
{
System.out.println(value); // 10 — stampa il campo della classe
int value = 5; // la variabile locale oscura il campo della classe
System.out.println(value); // stampa 5, non 10
}
}
In questo esempio, quando scriviamo int value = 5;, dichiariamo una nuova variabile locale che ha priorità sul campo della classe con lo stesso nome. Quando si fa riferimento a value all’interno del metodo printValue(), verrà utilizzata la variabile locale, non il campo della classe.
Se è necessario accedere a un campo statico della classe, usa il nome della classe come prefisso:
class ShadowDemo
{
static int value = 10; // campo statico della classe
void printValue()
{
System.out.println(value); // 10 — campo della classe
int value = 5;
System.out.println(value); // 5 — variabile locale
System.out.println(ShadowDemo.value); // 10 — campo statico della classe, accesso tramite 'ShadowDemo'
}
}
Se devi accedere a un campo non statico della classe, si usa la parola chiave this. Indica l’istanza corrente dell’oggetto.
class ShadowDemo
{
int value = 10;
void printValue()
{
System.out.println(value); // 10 — campo della classe
int value = 5;
System.out.println(value); // 5 — variabile locale
System.out.println(this.value); // 10 — campo della classe, accesso tramite 'this'
}
}
4. Pratica: modificatori di accesso e ambito di visibilità
Continuiamo a sviluppare l’applicazione didattica: un semplice sistema di gestione studenti. Impostiamo campi e metodi con diversi modificatori di accesso.
Esempio: classe Student
public class Student
{
public String name; // nome dello studente (visibile a tutti)
private int age; // età (visibile solo all'interno della classe)
public Student(String name, int age)
{
this.name = name;
this.age = age;
}
public void sayHello()
{
System.out.println("Ciao, mi chiamo " + name);
}
private void printSecret()
{
System.out.println("La mia età: " + age);
}
public void revealSecret()
{
printSecret(); // è possibile chiamare il metodo privato all'interno della classe
}
}
Uso della classe Student
public class Main
{
public static void main(String[] args)
{
Student s = new Student("Vasya", 20);
s.sayHello(); // OK: metodo pubblico
s.revealSecret(); // OK: metodo pubblico che chiama un metodo privato internamente
s.age = 30; // Errore! Il campo age è privato
s.printSecret(); // Errore! Il metodo printSecret è privato
}
}
5. Errori tipici nell’uso dei modificatori di accesso e dell’ambito di visibilità
Errore n. 1: tutto public — ed ecco il caos!
Se rendi pubblici tutti i campi e i metodi, rischi di perdere il controllo su chi e come modifica i tuoi dati. Rendi i campi private ed esponi solo ciò che è necessario.
Errore n. 2: Tentativo di usare una variabile fuori dal suo ambito di visibilità.
Per esempio, hai dichiarato una variabile all’interno di un metodo e poi provi ad accedervi dall’esterno — otterrai un errore di compilazione. Le variabili locali vivono solo nel loro blocco { ... }.
Errore n. 3: Conflitto di nomi (occultamento delle variabili).
Se in un metodo dichiari una variabile con lo stesso nome di un campo della classe, è facile confondersi su quale variabile stai usando. Usa this per indicare esplicitamente il campo della classe: this.value.
Errore n. 4: Tentativo di accedere a un metodo o campo private da un’altra classe.
Se un metodo o un campo è marcato come private, è accessibile solo all’interno della stessa classe. Il tentativo di accedervi dall’esterno causerà un errore di compilazione.
Errore n. 5: Dimenticare l’ambito di visibilità in un ciclo o in un blocco.
Una variabile dichiarata all’interno di un ciclo o di qualsiasi blocco { } vive solo all’interno di quel blocco. Fuori dal blocco non esiste.
GO TO FULL VERSION