Java passa por valor: sempre!

Foi publicada uma thread no The Server Side sobre um dos conceitos mais básicos da linguagem Java e que causa bastante confusão. Trata-se da passagem de parâmetros, que no caso da linguagem Java sempre ocorre por valor.

Exatamente, não existe passagem de parâmetros por referência na linguagem Java. Vejamos um exemplo básico:

class Test{
    public static void main(){
        int a = 10;

        soma5(a);

        System.out.println(a);
    }

    static void soma5(int num){
        num += 5;
    }
}

ou seja, como esperado, a soma dentro do método soma5 não afeta a variável original a, no escopo de main, de forma que será impresso o valor 10. Agora vejamos outro exemplo:

class Test{
    public static void main(){
        A a = new A();
        
        a.a = 10;

        soma5(a);

        System.out.println(a.a);
    }

    static void soma5(A a){
        a.a += 5;
    }
}

class A{
    int a;
}

Como esperado, o valor impresso será 15. Isso porque o objeto a foi passado por referência para o método soma5, correto ? ERRADO. E aqui está a armadilha! Objetos nunca são passados por parâmetro, objetos residem na heap e sempre devem ser acessados através de variáveis de referência. E são as referências que são passadas para os métodos. E da mesma maneira que variáveis de primitivos, elas são passadas por cópia para os métodos. Como o método que recebeu o parâmetro recebeu uma cópia, então o método altera o mesmo objeto.

É importante que este conceito fique bastante claro para evitar o seguinte tipo de erro:

class Test{
    public static void main(){
        A a = new A();
        
        a.a = 10;

        soma5(a);

        System.out.println(a.a);
    }

    static void soma5(A a){
        a = new A(); //esse objeto novo será marcado para gc assim que soma5 terminar
        a.a += 5;
    }
}

class A{
    int a;
}

nesse caso, a saída do programa é 10 porque o objeto original não será afetado pelo método soma5. Apesar do método receber a referência para o objeto criado em main este valor é perdido na atribuição a = new A() dentro de soma5. Porém, esta atribuição não afeta a variável “a” em main, justamente porque soma5 recebe uma cópia da referência.

A discussão original pode ser vista aqui:

http://www.theserverside.com/discussions/thread.tss?thread_id=61622

Anúncios

7 Responses to “Java passa por valor: sempre!”


  1. 1 Franco 10/03/2011 às 15:43

    Eu discordo do que é dito no post. Primitivos são passados por valor e objetos por referência.
    O fato de internamente ser passado uma cópia do valor da variável (ao invés de um ponteiro) é um detalhe interno da linguagem.

    Da mesma forma como os atributos de uma classe pai existem numa classe filha, mas não podem ser acessados. Significa: atributos não são herdados.

    Claro que esse assunto é uma questão de ponto de vista. As 2 argumentações fazem sentido e o importante é saber o que acontecerá com o parâmetro passado.

  2. 2 rodolfo4j 10/03/2011 às 16:20

    Franco, concordo quando você diz que o importante é saber o que acontece com os objetos passados. Mas é importante utilizarmos a terminologia correta para evitar erros como eu citei. Volto a frizar, objetos são alocados na heap, e ao chamar o método, o que é passado para o método é uma referência para um objeto, e não o objeto em si. Isso não é comportamento interno, é a semântica da linguagem. Quando uma linguagem suporta passagem por referência ela tem uma semântica específica para isso, como “var” no Delphi ou “ByVal” no VB. Isso não acontece com Java.

  3. 3 P 04/29/2012 às 10:09

    “Como o método que recebeu o parâmetro recebeu uma cópia, então o método altera o mesmo objeto.”

    Então, na prática a passagem não é por referência, mas age de forma similar, isso? Por isso tanta gente diz que, no caso de objetos, a passagem é por referência?

    Fiquei meio confuso!!

    • 4 rodolfo4j 06/21/2012 às 08:29

      É a mesma lógica dos ponteiros em C. Na linguagem C existe somente a passagem por valor, também. Quando queremos a passagem por referência passa-se uma cópia do ponteiro para aquela variável. O Java usa a mesma semântica, com a diferença de que são usados referências para objetos no lugar de ponteiros.

  4. 5 Luiz A. 06/21/2012 às 08:19

    legal! Será que ocorreria mesmo se a classe A fosse modificada assim?
    class A{
    int a=3;
    }

  5. 6 Henrique Santana 01/22/2014 às 12:24

    Ok, mas como faria algo parecido, tá dificil de achar uma solução. Nenhum blog fala sobre isso!


Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s




Categorias

Atualizações Twitter

Erro: o Twitter não respondeu. Por favor, aguarde alguns minutos e atualize esta página.


%d blogueiros gostam disto: