W3docs

Escopo de Variáveis em Java

Entenda onde uma variável Java é visível — escopo local, de instância, de classe (static) e de bloco.

O escopo de uma variável é a região do programa onde você tem permissão de usar seu nome. Um nome declarado dentro de um método não é visível em outro; um nome declarado dentro de um loop for não é visível após o loop. O compilador aplica essas regras com rigor — tente acessar um nome fora do seu escopo e o código não compilará.

Java tem três tipos principais de variáveis, cada uma com seu próprio escopo: variáveis locais (incluindo parâmetros), campos de instância e campos de classe. Este capítulo foca no escopo local, pois é ele que molda os métodos que você tem escrito.

Variáveis locais

Uma variável local é declarada dentro de um método ou bloco, e é visível apenas a partir do ponto de declaração até o final do bloco que a envolve:

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

Variáveis locais não são inicializadas pelo Java — você deve atribuir um valor antes de lê-las. O compilador rastreia a atribuição definida e se recusa a compilar a leitura de uma variável local possivelmente não inicializada:

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
}

Isso é diferente dos campos de instância e de classe, que o Java inicializa por padrão (números para 0, boolean para false, referências de objeto para null).

Escopo de bloco

Chaves definem um bloco. Variáveis declaradas dentro de um bloco são visíveis apenas dentro dele, incluindo blocos aninhados, mas não fora:

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
}

Isso se aplica a if, for, while, do-while, switch e a blocos { ... } simples que você escreve para agrupamento. A variável de loop de um for está no escopo apenas dentro do loop:

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

Se você precisar do índice após o loop, declare i fora:

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

Parâmetros de método

Parâmetros são variáveis locais que são inicializadas pelo chamador. Seu escopo é o corpo inteiro do método, da chave de abertura até a de fechamento:

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

Cada chamada tem seu próprio conjunto de slots de parâmetros, portanto chamadas recursivas não interferem umas nas outras.

Sombreamento

Java proíbe declarar uma variável local com o mesmo nome de uma que já está no escopo no mesmo bloco ou em um bloco externo do mesmo 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
  }
}

Isso é mais restritivo do que o que muitas linguagens permitem — Java assume que reutilizar um nome dentro de um método é um erro. (Campos de instância e de classe podem ser sombreados por variáveis locais de mesmo nome; abordaremos isso na parte de POO do livro.)

Note que dois blocos irmãos podem reutilizar um nome, porque seus escopos não se sobrepõem — nenhum é visível dentro do outro:

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

Tempo de vida vs. escopo

Escopo é onde você pode usar o nome. Tempo de vida é por quanto tempo o armazenamento subjacente existe. Eles geralmente coincidem — quando uma variável local sai do escopo, seu slot desaparece — mas para objetos a distinção 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

A variável s desaparece, mas o objeto String ao qual ela se referia ainda está vivo — o chamador mantém uma referência, portanto o coletor de lixo não o recolherá. Variáveis locais limitam nomes, não tempos de vida de objetos.

Um vislumbre de campos de instância e de classe

Dentro de uma classe, ao lado dos métodos, você pode declarar campos — variáveis cujo escopo é a classe inteira. Existem dois tipos:

  • Campos de instância pertencem a cada objeto criado a partir da classe. Cada Dog tem seu próprio name e age.
  • Campos de classe (declarados como static) pertencem à própria classe; existe uma cópia compartilhada.
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
  }
}

Não vamos nos aprofundar aqui — Classes e Objetos apresenta a própria classe, e Atributos de Classe aborda campos de instância adequadamente. Em resumo: campos são visíveis em toda a classe; variáveis locais são visíveis apenas no bloco em que foram declaradas.

Um exemplo prático

java— editable, runs on the server

O que vem a seguir

O escopo diz onde um nome vive. A próxima questão — depois de passar um argumento para um método — é o que o método realmente possui. O capítulo sobre passagem por valor esclarece a confusão mais comum em Java: o que realmente acontece quando você passa uma referência de objeto.

Prática

Prática
Onde é visível uma variável declarada dentro de um bloco if?
Onde é visível uma variável declarada dentro de um bloco if?
Was this page helpful?