Salve
No melhor estilo Nerd, neste fim de semana, em um BoF*, rolou o assunto de como as linguagens passam as variáveis para os métodos (functions, procedures, ). Estavam presentes programadores PHP, C e Java (eu).
Tudo ia bem, até por que entendo pouco de PHP e C, foi então que chegamos nas linguagens orientadas a objeto (eu sei que PHP é orientada a objetos -tem suporte pelo menos- mas quem usa?).
A discussão rola na internet também, e a pergunta que não quer calar é:
"Java passa as variáveis por valor ou por referência?"
Obs.: Passar por valor é às vezes chamado de "Passar por cópia".
Como funciona no Java -e maioria de linguagens orientadas a objetos-:
Imagine a seguinte situação:
int x = 12;
int y = x;
System.out.println(x);
System.out.println(y);
Este caso é um exemplo com tipos primitivos, e a resposta será:
12
12
E se decorrer eu adicionar:
y = 24;
System.out.println(x);
System.out.println(y);
A resposta será:
12
24
Sim, na linha em que declaramos y = x, a variável y é colocada na pilha e logo após recebe uma cópia do valor de x, então tenho isso na pilha:
x = 12
y = 12
A alteração de uma, não influencia a alteração de outra, isto é passagem por valor. Então se y = 24, x continua sendo 12. y obteve uma cópia dos bits de x.
Contudo, a situação se complica um pouco quando falamos de objetos, imagine a situação;
Cliente x = new Cliente();
x.setNome("Juliana Paes");
Cliente y = x;
x.setNome("Débora Secco");
System.out.println(x.getNome());
System.out.println(y.getNome());
A resposta será:
Débora Secco
Débora Secco
AHA! Então passou por referência! NÃO, passou por cópia.
Quando falamos em referência, referência = variável, não o Objeto no Heap. O que aconteceu neste caso foi o seguinte:
Memória ----------------------------------------+
Stack -------+ |
x = EF4EA3 | |
y = EF4EA3 | |
|
Heap ----------------------------------------+ |
+EF4EA3---------+ | |
| Cliente | | |
| Juliana Paes | | |
+---------------+ | |
------------------------------------------------+
As variáveis contém uma referência para o objeto no heap, que tem um ID indeterminável (só a JVM sabe, provavelmente um número de 32 ou 64 bits), logo na declaração das variáveis:
x = referência para objeto EF4EA3 no Heap
y = x //y = EF4EA3
Ou seja, y tem uma cópia do valor de x, o mesmo caso da cópia dos bits, que é a referência, o "id", do objeto. Para ilustar imagine esta situação:
Cliente x = new Cliente();
x.setNome("Juliana Paes");
Cliente y = x;
x = new Cliente();
x.setNome("Débora Secco");
System.out.println(x.getNome());
System.out.println(y.getNome());
Qual é a saída? Bem, está abaixo:
Débora Secco
Juliana Paes
Dois objetos foram criados, usando a variável x. No primeiro instante, y obteve uma cópia do valor de x, uma referência para Juliana Paes. Mais tarde, x recebeu um novo cliente, logo, uma nova referência a outro objeto no Heap, e esta alteração no valor de x não altera o valor de y, isto é o que quero dizer com passagem por valor.
Cada variável tem um valor, que é a referência a um objeto, não o próprio objeto (isto é bem básico).
Na passagem para métodos, acontece o mesmo:
// em algum lugar
Cliente x = new Cliente();
x.setNome("Juliana Paes");
changeCliente(x);
System.out.println(x.getNome());
//
public void changeCliente(Cliente x) {
x = new Cliente();
x.setNome("Débora Secco");
}
Qual é a saída do console?
Ora, Juliana Paes, claro. Existem duas variáveis com o nome x, uma fora do método, e outra, local, dentro do método. A mudança da variável interna, não afeta a externa, afinal, ela tem uma cópia do valor.
// em algum lugar
int x = 18;
change(x);
System.out.println(x);
//
public void change(int x) {
x = 9;
}
A saída é 18.
Algumas linguagens permitem usar, alternativamente, a passagem por referência, como a C#.
Ilustrando:
// em algum lugar
int x = 18;
change(x);
Console.WriteLine(x);
//
public void change(ref int x) {
x = 9;
}
A saída é 9. A diferença foi o uso da palavra-chave ref antes de declarar o parâmetro.
Em VB.NET, para passar por valor (default) seria assim:
Sub Change(ByVal x As Integer())
// faz algo
End Sub
E por referência:
Sub Change(ByRef x As Integer())
// faz algo
End Sub
Obs. 1: Não conheço muito a sintaxe do VB, se alguém detectar um erro notifique-me por favor.
Obs. 2: Não entrei em detalhes como o de objetos distribuídos, em que o objeto é serializado e enviado uma cópia de um espaço de memória para outro (ex.: de uma JVM para outra). Isto é uma condição excepcional.
Obs. 3: Relacionado à obs 2, é por isso que usamos interfaces locais sempre que possível, e interfaces remotas só quando for estritamente necessário (EJB, etc).
Resumindo, Java passa por valor, não por referência.
Este assunto é complicado de explicar, confuso e difícil de entender geralmente, mas seu conhecimento é um fundamento.
Dúvidas, críticas, correções, sugestões, fiquem a vontade.
E, falando em referências, leitura recomendada:
Nenhum comentário:
Postar um comentário