[Resolvido] Dúvida com variáveis de referência

Comprei o livro Use a cabeça java, e nessa parte das variáveis de referência dei uma parada e vim pesquisar mais para entender bem. Então peguei um exemplo que tem um trecho que realmente não estou entendendo com funciona, fiquei confuso na verdade.

O código:

class Retangulo {
      int ladoA;
      int ladoB; 
}

public static class TestAtribuicao {
      //variável de instância
      Retangulo retangulo3 = new Retangulo();

      public static void main(String[] args) {
            //variáveis locais
            Retangulo retangulo = new Retangulo();
            Retangulo retangulo2 = new Retangulo();
            TestAtribuicao test = new TestAtribuicao();
           
            //um dos objetos recebem os valores
            retangulo.ladoA = 5;
            retangulo.ladoB = 10;
           
            /* retangulo2 e retangulo3 passam a 
             * apontar para o mesmo objeto que 
             * retangulo */
            **retangulo = retangulo2;**  // Aqui neste ponto entendo que retangulo recebe de retangulo 2
            test.retangulo3 = retangulo;
           
            /* um valor é alterado em retangulo e,
             * como todas as tres variáveis apontam 
             * para o objeto, a alteração é vista
             * por todas as tres variáveis */
            retangulo.ladoA = 6;
            /* a regra independe de variável local ou
             * global */
            **System.out.println(retangulo2.ladoA); //6** // A dúvida é como esse retangulo2 recebe 6
            System.out.println(test.retangulo3.ladoA);//6
           
      }    
}

Cheguei a fazer um teste criando " retangulo2.ladoA = 8 ;"
E indicando uma saída:

retangulo = retangulo2;
System.out.println(retangulo2.ladoA);
System.out.println(retangulo.ladoA);

Neste caso imprime:

8
8
6
6

Tem a explicação no código, mas como o retangulo2 recebe o valor 6 no final que não entendi, e no que adicionei extra, tanto retangulo quanto retangulo2 recebem 8 na saída.

Seu comentário está certo, mas depende o que você acha que é retangulo.

A variável retangulo não contem os valores ladoA e ladoB. Ele é uma referencia (chamado de ponteiro em outras linguagens) para o lugar na memória onde estão os valores. Quando você atribui retangulo2 a retangulo, os valores não são copiados. Somente agora você tem 2 variáveis que apontam, ou referenciam, os mesmos dados.

Então quando você modifica os valores, seja usando retangulo ou retangulo2, ambos apontam para a o mesmo objeto, e ao acessar o valor posteriormente seja usando retangulo ou retangulo2, o valor vai estar mudado.

http://www.javabuilding.com/academy/java-language/objectos-variaveis-e-referencias.html

É uma duvida comum, pois isso não é evidente em Java pois ele esconde essa diferença usando a mesma sintaxe para variáveis que são ponteiros e que são valores diretos, coisa que não ocorre em linguagens como C, C++ ou Pascal, por exemplo. Mas em java toda variável que não são de tipos básicos (int, char, etc), e são de classes, declaram na verdade uma referencia.

1 curtida

Obrigado por responder.

Então seria correto eu pensar nessa atribuição:
retangulo.(acessa) ladoA =(com seu) valorX
retangulo2 se iguala a retangulo, ambos recebem saída valorX
ladoA = valorY
retangulo2 e retangulo recebem saída valorY

Então para tornar mais prático o pensamento, o sinal de atribuição poderia ser pensado como igualdade neste caso?
Eu entendi o que disse, só dei esse exemplo para ver se pode ser usado para não gerar tanta dúvida no começo.
Realmente é um pouco confuso por causa do costume de ver do lado esquerdo receber algo do valor direito, e neste
caso é como se retangulo convida-se retangulo2 para a festa.

Isso, o retangulo2 abandona os dados que ele fazia referencia originalmente, deixando de lado o objeto que ele apontava originalmente, e passa a servir para acessar os dados do mesmo objeto apontado pela variável retangulo.

Não entendi bem teu exemplo, mas vou tentar explicar como funciona por baixo dos panos pra ver se não fica duvida.


Como isso funciona é assim, uma variável do tipo int, ou float (tipos básicos do Java) tem um valor dela. Ela NÃO é uma referencia. Ela tem um valor de fato armazenado nela, no caso um valor inteiro para int, ou um valor decimal para float e assim vai.

Já para variáveis de tipos não-básicos, como é o caso de seu retangulo, ela também tem um valor só dela. Mas esse valor não é um objeto, o valor dentro de uma variável de referencia é o endereço de memória onde está o objeto a que a variável faz referência. Ou seja, o valor de uma variável como retangulo é um valor numérico (numérico num sentido mais amplo, não confundir com int), e esse valor numérico é a posição de memoria do objeto que ele referencia.

O Java dificulta entender isso, porque esconde o fato, e até por motivos históricos faziam propaganda de que “Java não tem ponteiros”, e por isso chamam de “referencia” os ponteiros. Mas é o mesmo conceito.

Então, voltando à sua duvida. Quando você faz retangulo = retangulo2. O que acontece é que é copiado NÃO a instancia do objeto Retangulo que possui ladoA e ladoB, mas é copiado o valor numérico que está em retangulo2, que é um endereço de memória, e agora tanto retangulo quanto retangulo2 possuem o mesmo endereço e o Java permite acessar com isso o mesmo objeto através das 2 variáveis.

Ou seja, acontece o mesmo que se fosse um int, a diferença é que o valor armazenado e copiado na atribuição tem um significado especial e o Java permite acessar através desse endereço o objeto de forma automática.

Então a atribuição não funciona diferente, dos tipos básicos, se você entende que tem ali escondido não um objeto na variável, mas um valor de endereço de memória, que serve para referenciar ou apontar para um objeto.

http://www.javabuilding.com/img/ilust/stackHeap.png

1 curtida

Deixa eu ver se entendi.

// retangulo, retangulo2 e retangulo3 estão apontando direto para o objeto Retangulo()
// Neste momento todos podem acessar ladoA e ladoB
Retangulo retangulo3 = new Retangulo();
Retangulo retangulo = new Retangulo();
Retangulo retangulo2 = new Retangulo();

// test usa retangulo3 para chegar ao objeto Retangulo() através da referência retangulo
TestAtribuicao test = new TestAtribuicao();

// Aqui então o retangulo2 está na posição 15 da memória por exemplo, passando essa posição para
// retangulo, que por sua vez test.retangulo3 também vai receber a posição 15 de memória de retangulo2
// através de retangulo.
retangulo = retangulo2; // retangulo2 passa posição 15 »»» retangulo que passa posição 15 »»» retangulo3
test.retangulo3 = retangulo; // test acessa ladoA na posição 15

Se é o que entendi segundo suas explicações, o valor original usado de memória é de retangulo2?
Acho que estou quase entendendo o conceito, o que errei por favor me corrija.

Até onde entendi da tua explicação acho que você compreendeu sim.

Bom, muito obrigado pela paciência e explicações.
Vou seguir os estudos.