W3docs

Ámbito de variables en Java

Aprende dónde es visible una variable en Java: ámbito local, de instancia, de clase (static) y de bloque.

El ámbito de una variable es la región del programa donde se permite usar su nombre. Un nombre declarado dentro de un método no es visible desde otro; un nombre declarado dentro de un bucle for no es visible después del bucle. El compilador aplica estas reglas estrictamente — intenta acceder a un nombre fuera de su ámbito y el código no compilará.

Java tiene tres tipos principales de variables, cada una con su propio ámbito: variables locales (incluidos los parámetros), campos de instancia y campos de clase. Este capítulo se centra en el ámbito local, ya que es lo que da forma a los métodos que has estado escribiendo.

Variables locales

Una variable local se declara dentro de un método o un bloque, y es visible únicamente desde el punto de declaración hasta el final del bloque que 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()

Las variables locales no son inicializadas por Java — debes asignar un valor antes de leerlas. El compilador realiza un seguimiento de la asignación definitiva y se niega a compilar la lectura de una variable local posiblemente no asignada:

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
}

Esto es diferente de los campos de instancia y de clase, que Java inicializa por defecto (números a 0, boolean a false, referencias a objetos a null).

Ámbito de bloque

Las llaves definen un bloque. Las variables declaradas dentro de un bloque son visibles solo dentro de ese bloque, incluyendo los bloques anidados pero no fuera de él:

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
}

Esto aplica a if, for, while, do-while, switch y a bloques { ... } simples que escribas para agrupar. La variable de control de un bucle for tiene ámbito solo dentro del bucle:

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

Si necesitas el índice después del bucle, declara i fuera:

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

Parámetros de método

Los parámetros son variables locales que resultan ser inicializadas por quien llama al método. Su ámbito es todo el cuerpo del método, desde la llave de apertura hasta la de cierre:

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

Cada llamada obtiene su propio conjunto de ranuras de parámetros, por lo que las llamadas recursivas no interfieren entre sí.

Sombreado

Java prohíbe declarar una variable local con el mismo nombre que una que ya está en ámbito en el mismo bloque o en un bloque exterior del mismo método:

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

Esto es más estricto de lo que permiten muchos lenguajes — Java asume que reutilizar un nombre dentro de un método es un error. (Los campos de instancia y de clase pueden ser sombreados por variables locales del mismo nombre; lo veremos en la parte de POO del libro.)

Ten en cuenta que dos bloques hermanos pueden reutilizar un nombre, porque sus ámbitos no se solapan — ninguno es visible dentro del otro:

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

Vida útil vs. ámbito

El ámbito es donde puedes usar el nombre. La vida útil es cuánto tiempo existe el almacenamiento subyacente. Generalmente coinciden — cuando una variable local sale de ámbito, su ranura desaparece — pero para los objetos la distinción importa:

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 desaparece, pero el objeto String al que hacía referencia sigue vivo — el invocador tiene una referencia, por lo que el recolector de basura no lo recuperará. Las variables locales limitan los nombres, no las vidas útiles de los objetos.

Un vistazo a los campos de instancia y de clase

Dentro de una clase, junto a los métodos, puedes declarar campos — variables cuyo ámbito es toda la clase. Hay dos variedades:

  • Campos de instancia pertenecen a cada objeto creado a partir de la clase. Cada Dog tiene su propio name y age.
  • Campos de clase (declarados static) pertenecen a la clase en sí; hay una sola copia compartida.
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
  }
}

No profundizaremos aquí — Clases y objetos presenta la clase en sí, y Atributos de clase cubre los campos de instancia correctamente. En resumen: los campos son visibles en toda la clase; las variables locales solo son visibles en el bloque donde se declaran.

Un ejemplo completo

java— editable, runs on the server

Qué viene a continuación

El ámbito indica dónde vive un nombre. La siguiente pregunta — una vez que has pasado un argumento a un método — es qué tiene realmente el método. El capítulo sobre paso por valor aclara la confusión más común en Java: qué ocurre realmente cuando pasas una referencia a un objeto.

Práctica

Práctica
¿Dónde es visible una variable declarada dentro de un bloque if?
¿Dónde es visible una variable declarada dentro de un bloque if?
Was this page helpful?