1. Introdução
Em diferentes linguagens de programação, existem duas formas principais de passagem de parâmetros para funções (ou métodos):
- Por valor: a função recebe uma cópia do valor da variável. Se a função alterar o parâmetro, o original não muda.
- Por referência: a função recebe uma “referência” (ponteiro) para o objeto original. As mudanças dentro da função se refletem no original.
Em Java, TODOS os parâmetros são passados por valor!
Mas há um detalhe: quando passamos tipos primitivos (int, double, boolean etc.), o que é copiado é o próprio valor. Já quando passamos tipos de referência (por exemplo, arrays ou objetos), o que é copiado é o valor da referência (isto é, o “endereço” do objeto na memória), e não o objeto em si.
Se você sentir que o cérebro está derretendo, não se preocupe — já vamos organizar tudo e mostrar com exemplos!
2. Tipos primitivos: o valor é copiado
Vamos começar com o simples: o que acontece se tentarmos alterar o valor de uma variável do tipo int dentro de um método?
public class Demo
{
public static void main(String[] args)
{
int number = 5;
changeValue(number);
System.out.println(number); // O que será impresso?
}
public static void changeValue(int n)
{
n = 42;
}
}
Resultado: será impresso 5.
Por quê?
O método changeValue recebe uma CÓPIA do valor da variável number. Dentro do método, alteramos apenas a cópia (n); a variável original number em main permanece intocada.
Analogia
Imagine que você deu a um amigo uma fotocópia do passaporte, e não o original. O amigo pode desenhar bigodes na cópia o quanto quiser — seu passaporte verdadeiro continua o mesmo!
3. Tipos de referência: a referência é copiada
Agora, vamos tentar o mesmo com um array:
public class Demo
{
public static void main(String[] args)
{
int[] numbers = {1, 2, 3};
changeFirst(numbers);
System.out.println(numbers[0]); // O que será impresso?
}
public static void changeFirst(int[] arr)
{
arr[0] = 99;
}
}
Resultado: será impresso 99.
Por quê?
O método changeFirst recebe uma cópia da REFERÊNCIA para o array numbers. Ambos os nomes (numbers em main e arr no método) apontam para o mesmo array na memória. Por isso, quando alteramos um elemento do array dentro do método, a alteração fica “visível” fora.
Visualização
main: numbers ──► [1, 2, 3]
▲
│
changeFirst: arr ──┘
Ao alterar arr[0], na verdade estamos alterando numbers[0], porque ambos apontam para o mesmo objeto.
4. Mas se você trocar a própria referência — o objeto original não mudará!
Vamos tentar assim:
public class Demo
{
public static void main(String[] args)
{
int[] numbers = {1, 2, 3};
replaceArray(numbers);
System.out.println(numbers[0]); // O que será impresso?
}
public static void replaceArray(int[] arr)
{
arr = new int[] {10, 20, 30};
}
}
Resultado: imprimirá 1.
Por quê?
No método replaceArray, a variável arr passa a apontar para um novo array, mas isso não afeta a variável numbers em main.
Elas estavam ligadas por uma referência, mas, quando dentro do método fazemos arr = ..., isso é apenas uma mudança local.
Analogia
É como se você e seu amigo tivessem a mesma chave de casa. O amigo faz uma nova chave para si, mas sua chave antiga continua a mesma — e a porta continua sendo a mesma.
5. Exemplos para fixar: não é possível “trocar de lugar” dois int via método
Muitos iniciantes tentam escrever um método para trocar dois números de lugar, mas não conseguem:
public class Demo
{
public static void main(String[] args)
{
int a = 5, b = 10;
swap(a, b);
System.out.println(a + " " + b); // Esperado: 10 5, e na realidade?
}
public static void swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
}
Resultado: serão impressos 5 10.
Por quê?
Porque em swap chegam cópias das variáveis a e b. Tudo o que fazemos dentro de swap afeta apenas essas cópias, não os originais.
6. Mas com arrays dá para alterar o conteúdo!
Veja a forma correta de trocar valores de lugar em um array:
public class Demo
{
public static void main(String[] args)
{
int[] arr = {5, 10};
swap(arr);
System.out.println(arr[0] + " " + arr[1]); // Esperado: 10 5
}
public static void swap(int[] arr)
{
int temp = arr[0];
arr[0] = arr[1];
arr[1] = temp;
}
}
Resultado: imprimirá 10 5.
Por quê?
Porque alteramos o conteúdo do objeto (array) para o qual apontam tanto a variável original quanto o parâmetro do método.
7. Demonstração: objetos e seus campos
Já vimos os arrays. E quanto aos objetos de classes próprias? É exatamente igual!
class Box
{
int value;
}
public class Demo
{
public static void main(String[] args)
{
Box box = new Box();
box.value = 7;
changeBox(box);
System.out.println(box.value); // O que será impresso?
}
public static void changeBox(Box b)
{
b.value = 42;
}
}
Resultado: imprimirá 42.
Por quê?
Porque alteramos um campo do objeto para o qual a referência aponta.
O que acontece ao passar parâmetros para métodos
| O que passamos | Como é copiado | Pode alterar dentro do método? | As alterações são visíveis fora? |
|---|---|---|---|
| int, double e outros | Cópia do valor | Sim, mas apenas a cópia | Não |
| Array | Cópia da referência | Sim, se alterar os elementos | Sim |
| Objeto (classe) | Cópia da referência | Sim, se alterar os campos | Sim |
| Array/objeto | Cópia da referência | Não, se atribuir uma nova referência | Não |
8. Erros comuns
Erro nº 1: esperar que um int mude após a chamada do método. Muitos iniciantes pensam que, se passarem uma variável do tipo int a um método, poderão mudar seu valor dentro do método. Isso é incorreto: muda-se apenas a cópia!
Erro nº 2: tentar trocar de lugar dois int via método. Como já vimos, isso é impossível — apenas as cópias das variáveis trocam de lugar; os originais não são afetados.
Erro nº 3: tentar “substituir” um array via método. Se, dentro do método, você atribuir ao parâmetro-array um novo array (arr = new int[]{...}), isso não afetará o array original. Para “substituir” o array — é preciso retornar um novo array do método e atribuí-lo à variável no código chamador.
Erro nº 4: esquecer que é possível alterar o conteúdo do objeto. Se você passar um objeto (ou um array) — não se esqueça de que quaisquer mudanças em seus campos/elementos serão visíveis do lado de fora!
Erro nº 5: confusão com null. Se você passar ao método uma referência igual a null e tentar acessar seus campos — você terá um NullPointerException. Fique atento!
GO TO FULL VERSION