Atribuição a Variáveis de Referência


Uma variável que se refere a um objeto é uma variável de referência. Um recipiente que guarda essa variável contém apenas a forma de chegar ao objeto, ou seja, contém um endereço de memória que representa um objeto específico no heap, ou ainda o valor null, pois se uma variável de referência não receber nenhum valor ou receber explicitamente o valor null, o recipiente irá guardar a representação de bits de null.
É possível atribuir um objeto recém-criado a uma variável de referência. Nesse caso, ocorrem três coisas: cria-se uma variável de referência do tipo da variável; cria-se um novo objeto desse tipo no heap; e atribui-se esse objeto à variável de referência.
A variável de referência também pode receber o valor null, o que significa que essa variável não se refere a um objeto, ou seja, apenas foi criado um container que irá receber o endereço de memória de um objeto.

class Pessoa { }

class Aluno extends Pessoa { }

public class Atribuicao_Objetos {
     
      public static void main(String[] args) {
            /*Aluno é subclasse de Pessoa, ou
             *seja, tudo que Aluno tem, Pessoa
             *também tem */
            Pessoa pessoa = new Aluno();
            /*Erro - Pessoa é superclasse de
             *Aluno, ou seja, existem coisas
             *que Aluno tem e Pessoa não tem */
            Aluno aluno = new Pessoa();
      }

}


Atribuindo uma variável de referência (objeto) a outra

A atribuição de um objeto a outro funciona da mesma maneira que a atribuição de variáveis primitivas, ou seja, é feita uma cópia do conteúdo de uma variável para a outra. No caso de variáveis de referência, o conteúdo é o endereço de memória para acessar o objeto a que se refere.
Isso quer dizer que as duas variáveis estarão acessando o mesmo objeto na memória (heap), já que as duas estarão guardando o mesmo conteúdo (endereço). Por causa disso, se algo for modificado em um objeto, automaticamente o outro também será, já que apontam para a mesma instância. Trata-se de duas variáveis apontando para o mesmo objeto.

class Retangulo {
      int ladoA;
      int ladoB
}

public 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;
            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
            System.out.println(test.retangulo3.ladoA);//6
           
      }    
}


A única exceção para essa regra é a classe String. Nesse caso, é possível mudar o valor de uma instância que não afetará a outra, pois esta classe é tratada de uma forma diferente.
A explicação para isso é que quando uma variável de referência do tipo String é modificada, uma nova String é criada (ou uma String correspondente é criada no pool da String, deixando a original intacta), e, a referência utilizada para modificá-la, é atribuída a esse novo objeto.
Em outras palavras, no caso da String, enquanto um objeto for atribuído a outro sem haver modificações eles estarão apontando para o mesmo lugar, mas quando houver alguma modificação em qualquer um dos dois será criado um novo objeto, não afetando o outro.


public class TestAtribuicaoString {
      public static void main(String[] args) {
            String valor = "teste";
            String valor2 = valor;
            //as duas continuam com o mesmo valor
            //imprime: teste teste
            System.out.println(valor + " " +  valor2);
            /* quando o valor de uma delas é alterado,
             * uma nova referência é criada, não
             * afetando a outra variável */
            valor = "teste2";
            //imprime: teste2 teste
            System.out.println(valor + " " +  valor2);
      }
}

Fonte: SCJP Sun Certified Programmer for Java 6 Study Guide

0 comentários:

Postar um comentário