Fala Everson!
Não se preocupe, referências podem ser um assunto um tanto quanto confuso no início e é perfeitamente normal não compreender de primeira!
Para exemplificar, vamos pensar em como são armazenados objetos na memória do computador. Quando tratamos de tipos primitivos (int, double, char), ao atribuir uma variável na memória, é como se estivessemos guardando o valor dessas variáveis dentro da própria caixinha dela: quando escrevemos int x = 5
, na memória poderia ser representado assim:
Ou seja, dentro do mesmo espaço de memória é guardada a variável e o valor dela!
Mas quando falamos de variáveis de referências, a representação na memória fica um pouco diferente, pois quando usamos a instrução new Objeto()
, estamos criando um espaço na memória que representa um objeto:
Mas, ao utilizar o comando new Objeto()
, sem atribuí-lo a uma referência, esse objeto é criado, armazenado na memória, mas é impossível acessá-lo! É como se estivesse flutuando no vazio. Nesses casos, a Máquina Virtual Java deleta o objeto da memória, pois sabe que ele está ocupando um espaço de memória que não está sendo utilizado. Para acessar esse objeto, então, precisamos atribuir esse espaço de memória a uma variável, com o comando Objeto obj = new Objeto()
:
Quando utilizamos esse comando, criamos o objeto na memória e um outro espaço, que é a variável obj
. Essa variável, como descrito na imagem, aponta para o endereço de memória onde está o objeto criado. A partir desse momento, podemos acessar atributos e métodos do Objeto, a partir de sua referência obj
.
Portanto, podemos analisar o comando Objeto obj = new Objeto()
em três partes:
Objeto obj
: essa parte do comando cria na memória a variável de referência obj, sem atribuir nenhum endereço a ela.new Objeto()
: essa parte cria o objeto na memória, sem que ele seja atribuído a nenhuma variável- Por fim, o operador
=
de atribuição une as duas partes, e constrói a seta de referência da variável obj
para o objeto criado na memória.
Assim, construindo a situação descrita no diagrama.
Beleza, então nós temos agora uma variável obj
que aponta para um objeto do tipo Objeto() na memória, a partir do comando Objeto obj = new Objeto()
. Mas o que exatamente faz o comando Objeto y = obj
?
Bem, nesse caso, a gente conta com a criação da variável de referência (parte anterior ao operador de atribuição), no entanto não criamos o objeto durante essa atribuição, mas sim atribuímos a ele a mesma referência contida na variável obj
, ou seja, copiamos para dentro da variável y
o endereço de memória Objeto@3ab23f
:
Assim, nós temos duas variáveis que apontam para o mesmo objeto. Isso significa que para acessar o objeto guardado na memória no endereço Objeto@3ab23f
, podemos utilizar qualquer uma das variáveis: obj
ou y
. Por se tratar do mesmo objeto, qualquer alteração feita a partir de obj é sentida por y e vice-versa. Isto é, quando alteramos obj, ao acessar y vamos perceber a mudança feita por obj.
Por este motivo, no código de exemplo os valores das variáveis se alteram todos em conjunto: na verdade existe um único objeto, que é referenciado pelas três variáveis.
Em caso de dúvidas, fico à disposição.
Um grande abraço e bons estudos!
Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓. Bons Estudos!