W3docs

Portée des variables en Java

Comprenez où une variable Java est visible — portée locale, d'instance, de classe (statique) et de bloc.

La portée d'une variable est la région du programme où vous êtes autorisé à utiliser son nom. Un nom déclaré à l'intérieur d'une méthode n'est pas visible depuis une autre ; un nom déclaré à l'intérieur d'une boucle for n'est pas visible après la boucle. Le compilateur applique ces règles strictement — tentez d'accéder à un nom en dehors de sa portée et votre code ne compilera pas.

Java distingue trois grandes catégories de variables, chacune avec sa propre portée : les variables locales (y compris les paramètres), les champs d'instance et les champs de classe. Ce chapitre se concentre sur la portée locale, car c'est elle qui façonne les méthodes que vous avez écrites jusqu'ici.

Variables locales

Une variable locale est déclarée à l'intérieur d'une méthode ou d'un bloc, et n'est visible que depuis le point de déclaration jusqu'à la fin du bloc englobant :

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()

Les variables locales ne sont pas initialisées par Java — vous devez leur affecter une valeur avant de les lire. Le compilateur effectue un suivi de l'affectation définie et refuse de compiler la lecture d'une variable locale potentiellement non initialisée :

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
}

Cela diffère des champs d'instance et de classe, que Java initialise par défaut (les nombres à 0, boolean à false, les références d'objet à null).

Portée de bloc

Les accolades définissent un bloc. Les variables déclarées à l'intérieur d'un bloc ne sont visibles qu'à l'intérieur de ce bloc, y compris dans les blocs imbriqués, mais pas à l'extérieur :

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
}

Cela s'applique aux blocs if, for, while, do-while, switch, ainsi qu'aux blocs { ... } nus que vous écrivez pour regrouper du code. La variable de boucle d'un for n'est dans la portée qu'à l'intérieur de la boucle :

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

Si vous avez besoin de l'indice après la boucle, déclarez i à l'extérieur :

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

Paramètres de méthode

Les paramètres sont des variables locales qui se trouvent être initialisées par l'appelant. Leur portée est l'ensemble du corps de la méthode, de l'accolade ouvrante à l'accolade fermante :

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

Chaque appel dispose de ses propres emplacements de paramètres, de sorte que les appels récursifs ne se perturbent pas mutuellement.

Masquage (Shadowing)

Java interdit de déclarer une variable locale portant le même nom qu'une variable déjà dans la portée dans le même bloc ou un bloc englobant de la même méthode :

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
  }
}

C'est plus strict que ce que permettent de nombreux langages — Java suppose que réutiliser un nom à l'intérieur d'une méthode est une erreur. (Les champs d'instance et de classe peuvent être masqués par des variables locales du même nom ; nous aborderons cela dans la partie POO du livre.)

Notez que deux blocs frères peuvent réutiliser un nom, car leurs portées ne se chevauchent pas — aucun n'est visible à l'intérieur de l'autre :

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 */ }
}

Durée de vie vs. portée

La portée indique où vous pouvez utiliser le nom. La durée de vie indique combien de temps le stockage sous-jacent existe. Elles coïncident généralement — lorsqu'une variable locale sort de la portée, son emplacement disparaît — mais pour les objets, la distinction est 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 variable s disparaît, mais l'objet String auquel elle faisait référence est toujours en vie — l'appelant conserve une référence, de sorte que le ramasse-miettes ne le récupérera pas. Les variables locales limitent les noms, pas les durées de vie des objets.

Un aperçu des champs d'instance et de classe

À l'intérieur d'une classe, à côté des méthodes, vous pouvez déclarer des champs — des variables dont la portée est toute la classe. Il en existe deux types :

  • Les champs d'instance appartiennent à chaque objet créé à partir de la classe. Chaque Dog possède son propre name et age.
  • Les champs de classe (déclarés static) appartiennent à la classe elle-même ; il n'existe qu'une seule copie partagée.
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
  }
}

Nous n'irons pas plus loin ici — Classes et Objets présente la classe elle-même, et Attributs de classe couvre les champs d'instance en détail. En résumé : les champs sont visibles partout dans la classe ; les variables locales ne sont visibles que dans le bloc où elles sont déclarées.

Exemple pratique

java— editable, runs on the server

La suite

La portée vous indique où vit un nom. La question suivante — une fois qu'un argument a été passé à une méthode — est ce que la méthode reçoit réellement. Le chapitre sur le passage par valeur dissipe la confusion la plus courante en Java : ce qui se passe réellement lorsque vous passez une référence d'objet.

Exercices

Pratique
Où est visible une variable déclarée à l'intérieur d'un bloc if ?
Où est visible une variable déclarée à l'intérieur d'un bloc if ?
Was this page helpful?