W3docs

Scope delle variabili in Java

Scopri dove una variabile Java è visibile: scope locale, di istanza, di classe (static) e di blocco.

Lo scope di una variabile è la regione del programma in cui puoi usarne il nome. Un nome dichiarato all'interno di un metodo non è visibile da un altro; un nome dichiarato all'interno di un ciclo for non è visibile dopo il ciclo. Il compilatore applica queste regole in modo rigoroso — se provi a usare un nome al di fuori del suo scope, il codice non compilerà.

Java ha tre principali tipi di variabili, ciascuno con il proprio scope: variabili locali (inclusi i parametri), campi di istanza e campi di classe. Questo capitolo si concentra sullo scope locale, poiché è quello che caratterizza i metodi che hai scritto finora.

Variabili locali

Una variabile locale è dichiarata all'interno di un metodo o di un blocco, ed è visibile solo dal punto di dichiarazione fino alla fine del blocco che la contiene:

public static int demo() {
  int x = 1;            // x is in scope from here...
  System.out.println(x);
  return x;
}                       // ...to here

// System.out.println(x);  // ERROR: x not visible outside demo()

Le variabili locali non vengono inizializzate da Java — devi assegnare un valore prima di leggerle. Il compilatore tiene traccia dell'assegnazione definitiva e rifiuta di compilare la lettura di una variabile locale potenzialmente non assegnata:

public static void unassigned() {
  int n;
  // System.out.println(n);  // ERROR: variable n might not have been initialized
  n = 5;
  System.out.println(n);     // OK now
}

Questo è diverso dai campi di istanza e di classe, che Java inizializza con valori predefiniti (numeri a 0, boolean a false, riferimenti a oggetti a null).

Scope di blocco

Le parentesi graffe definiscono un blocco. Le variabili dichiarate all'interno di un blocco sono visibili solo al suo interno, compresi i blocchi annidati, ma non all'esterno:

public static void blocks() {
  int outer = 10;

  if (outer > 0) {
    int inner = 20;
    System.out.println(outer + inner);   // both visible
  }

  // System.out.println(inner);  // ERROR: inner is out of scope here
}

Questo vale per if, for, while, do-while, switch e per i blocchi { ... } che scrivi per raggruppare il codice. La variabile di ciclo di un for è nello scope solo all'interno del ciclo:

for (int i = 0; i < 3; i++) {
  System.out.println(i);
}
// System.out.println(i);  // ERROR: i is out of scope

Se hai bisogno dell'indice dopo il ciclo, dichiara i all'esterno:

int i = 0;
for (; i < 3; i++) {
  System.out.println(i);
}
System.out.println("stopped at " + i);

Parametri dei metodi

I parametri sono variabili locali che vengono inizializzate dal chiamante. Il loro scope è l'intero corpo del metodo, dalla parentesi graffa di apertura a quella di chiusura:

public static int square(int n) {     // n is in scope from here...
  return n * n;
}                                     // ...to here

Ogni chiamata riceve il proprio set di slot per i parametri, quindi le chiamate ricorsive non si interferiscono tra loro.

Shadowing

Java vieta la dichiarazione di una variabile locale con lo stesso nome di una già nello scope nel medesimo blocco o in un blocco esterno dello stesso metodo:

public static void clash() {
  int x = 1;
  // int x = 2;   // ERROR: variable x is already defined
  if (true) {
    // int x = 3; // ERROR: x is in scope from the outer block
  }
}

Questo è più restrittivo di quanto molti linguaggi consentano — Java presuppone che riutilizzare un nome all'interno di un metodo sia un errore. (I campi di istanza e di classe possono essere oscurati da variabili locali con lo stesso nome; lo vedremo nella parte OOP del libro.)

Nota che due blocchi fratelli possono riutilizzare un nome, perché i loro scope non si sovrappongono — nessuno è visibile all'interno dell'altro:

public static void siblings() {
  for (int i = 0; i < 3; i++) { /* first i */ }
  for (int i = 0; i < 3; i++) { /* a fresh i — legal, the first is gone */ }
}

Lifetime vs. scope

Lo scope indica dove puoi usare il nome. Il lifetime indica per quanto tempo esiste lo storage sottostante. Di solito coincidono — quando una variabile locale esce dallo scope, il suo slot scompare — ma per gli oggetti la distinzione è importante:

public static String makeName() {
  String s = new String("Ada");   // s in scope here
  return s;
}                                  // s out of scope, but the String object lives on

La variabile s scompare, ma l'oggetto String a cui faceva riferimento è ancora vivo — il chiamante ha un riferimento, quindi il garbage collector non lo recupererà. Le variabili locali limitano i nomi, non i lifetime degli oggetti.

Un'introduzione ai campi di istanza e di classe

All'interno di una classe, insieme ai metodi, puoi dichiarare campi — variabili il cui scope è l'intera classe. Esistono due varianti:

  • I campi di istanza appartengono a ogni oggetto creato dalla classe. Ogni Dog ha il proprio name e age.
  • I campi di classe (dichiarati static) appartengono alla classe stessa; esiste una sola copia condivisa.
public class Counter {
  private static int totalCreated = 0;   // class field — one shared
  private int value = 0;                 // instance field — one per Counter

  public Counter() {
    totalCreated++;
  }

  public void inc() {
    value++;                              // refers to this instance's field
  }
}

Non approfondiremo qui — Classi e Oggetti introduce la classe stessa, e Attributi di Classe tratta i campi di istanza in modo appropriato. In sintesi: i campi sono visibili ovunque nella classe; le variabili locali sono visibili solo nel blocco in cui sono dichiarate.

Un esempio pratico

java— editable, runs on the server

Cosa c'è dopo

Lo scope ti dice dove vive un nome. La prossima domanda — una volta passato un argomento a un metodo — è cosa ha effettivamente il metodo. Il capitolo sul passaggio per valore chiarisce la confusione più comune in Java: cosa succede davvero quando passi un riferimento a un oggetto.

Esercitati

Pratica
Dove è visibile una variabile dichiarata all'interno di un blocco if?
Dove è visibile una variabile dichiarata all'interno di un blocco if?
Was this page helpful?