Passagem de argumentos por referência

Olá! Alguém pode me indicar algum documento da SUN (white paper, JSR, entrevista, tutorial – qualquer coisa serve) que explique porque Java não tem passagem de argumentos por referência?

Alguém do fórum poderia argumentar sobre o assunto? Favor se ater a fatos, ok? Coisas do tipo “Não tem porque não precisa!” não constribuem para a discussão.

Grato,
Jefferson Andrade.

Caro colega

Normalmente, quando dizemos que a passagem de um parametro é sempre por referencia quando se trata de um objeto estamos enganados, mas não completamente.

Olha só que interessante:

Em java, quando criamos um objeto de uma classe, na verdade estamos criando um indicador para um objeto que está instanciado na memória, ou seja, estamos nos referindo a um endereço. quando passamos esse indicador como um parametro, ao modificá-lo, estamos modificando diretamente o objeto, o que nos dá a impressão de estar passando o parametro por referência.

Sendo assim, o JAVA não implementa passagem de objetos por parametros porque não é necessário.

Os parâmetros que não são objetos são passados por valor.
Já no caso de objetos é passado por referência.

Veja abaixo.

public class Teste {

String label;

void alteraParametro(Teste ox, int x){
x++;
ox.label = “alterei”;
}

public static void main(String[] arg){
int a;
a = 1;

Teste objetoqq = new Teste();
objetoqq.label = “nao alterado”;

Teste teste = new Teste();
teste.alteraParametro(objetoqq,a);

System.out.println(“String =”+objetoqq.label+", int ="+a);
}

}

:smiley:
Falou,
Fábio

Olá a todos!

Diferentemente de outras linguagens, Java não permite que o programador escolha entre passar cada argumento por valor ou referência. As variáveis dos tipos de dados primitivos sempre são passados por valor. Os objetos não são passados para métodos; em vez disso, são passados aos métodos referências para objetos. AS PRÓPRIAS REFERÊNCIAS SÃO PASSADAS POR VALOR - uma cópia da referência é passada para o método chamado. Quando um método recebe uma referência para um objeto, o método pode manipular o objeto diretamente.
Mais:
Ao retornar as informações de um método através de uma instrução “return”, variáveis dos tipos de dados primitivos sempre são retornados por valor (isto é, é devolvida uma cópia) e os objetos são retornados por referência (isto é, é devolvida uma referência para o objeto).

[ ]'s

…e eu qnd vim do C pro Java fiquei louco com isso, achei uma limitação… acostumado a usar tudo com ponteiros pra sair mais otimizado, mas com o tempo acostuma… hehehe, oq vc pode fazer (mas eu acho muito má pratica) é passar um array de um unico elemento int/long/float/double oq seja pro metodo… dai, ele vai mandar um objeto array, e vai acessar esse dado como se fosse por referencia…

Olá Matheus,

Uma correção sobre mandar um objeto array:

Os arrays são tratados como objetos em java; portanto, os arrays são passados aos métodos por referência - um método chamado pode acessar os elementos dos arrays originais do chamador. O nome do array, é na verdade, uma referência para o objeto que contém os elementos do array (lembrando: AS PRÓPRIAS REFERÊNCIAS SÃO PASSADAS POR VALOR) e a variável de instância length, que indica o número de elementos do array.

Passar arrays por referência faz sentido por razões de desempenho. Se os arrays fossem passados por valor, uma cópia de cada elemento seria passada. Para os arrays grandes passados com frequência, isso desperdiçaria tempo e consumiria considerável capacidade de armazenamento para as cópias dos arrays.

{ ]'s

Pessoal, agradeço as respostas e a disposição em ajudar. Mas quando disse que respostas do tipo “Não tem porque não precisa.” não ajudavam na discussão, eu estava falando sério.

Não sou exatamente novato em Java. Na verdade já trabalho com a linguagem desde 96, o que me confere uma certa experiência. Sei perfeitamente que quando se declara

String s = "oi!";

O ‘s’ é uma referência (ponteiro se preferirem) ao objeto em memória, e que a declaração

String t = s;

Não copia o “conteúdo” de ‘s’ para ‘t’, mas ao invés faz com que ‘t’ seja uma segunda referência para o mesmo objeto e todas as demais pérolas que foram colocadas nas respostas. Sei perfeitamente como contornar as limitações que a falta de argumentos por referência impõem a linguagem. A pergunta não é sobre esses tópicos. A pergunta é

“POR QUE Java não tem passagem de argumentos por referência.”

Quanto a questão de não precisar porque dá para simular com arrays, porque objetos são sempre passados por referência, etc. Digamos que eu queira trocar o valor de duas variáveis (operação extremamente comum em vários algoritmos). O óbvio para quem está habituado a programação estruturada (da qual a OO é uma extensão) é criar uma função que realize a operação. Em Java essa operação trivial (e muito útil) vira um “inferno”. Vejam o código abaixo:

Em C:

void swap(int *a, int *b) {
    int x = *a;
    *a = *b;
    *b = x;
}

Em pascal:

procedure swap(var a, b: integer);
var x: integer;
begin
    x := a;
    a := b;
    b := x;
end;

Em C++ usando templates (generics)

template <T> void swap(T &a, T &b) {
    T x = a;
    a = b;
    b = x;
}

Em Java:

Tentativa 1:

void swap(int a, int b) {
    int x = a;
    a = b;
    b = x;
}

Falha por razões óbvias.

Tentativa 2:

<code>
void swap(Integer a, Integer b) {
Integer x = a;
a = b;
b = x;
}
</code>

Também falha, pois apesar de a referência me permitir alterar o objeto (nem isso nesse caso porque objetos Integer não tem acessores – setters e getters – são objetos constantes) a referência em si é passada por VALOR o que significa que as atribuições a ‘a’ e ‘b’ serão perdidas ao final do método.

Tentativa 3:

void swap&#40;int&#91;&#93; v&#41; &#123;
    assert&#40;v.length == 2&#41;;
    int x = v&#91;0&#93;;
    v&#91;0&#93; = v&#91;1&#93;;
    v&#91;1&#93; = v&#91;0&#93;;
&#125;

O método realiza a operação desejada, inclusive com persistência do efeito colateral após o final da execução, entretanto se interpõe um outro problema. A sintaxe desejada para a função seria.

    p = /* algum valor */;
    ...
    q = /* um outro valor */;
    ....
    swap&#40;p, q&#41;;    /* valores de p e q são trocados */

A versão do método da tentativa 3 não funciona. Vejam o código abaixo:

    int&#91;&#93; w = &#123;p, q&#125;;
    swap&#40;w&#41;;

Quando o vetor ‘w’ acima é construído ele armazena os VALORES de p e q e não referências. Desta forma, quando o método ‘swap’ for executado ele irá trocar com sucesso o conteúdo das posições 0 e 1 do vetor ‘w’ mas não o conteúdo das variáveis p e q.

É evidente que é possível trabalhar com a linguagem mesmo com esta limitação. Certamente não é NECESSÁRIO ter passagem de argumentos por referência, entretanto TODAS as linguagens estão CHEIAS de coisas que não são necessárias, mas que facilitam o uso da linguagem. Estritamente falando, nenhuma linguagem precisa de mais do que IF e RECURSÃO. Nem a atribuição de valores é necessária (lembram das aulas de Teoria da Computação e de Linguagens Formais e Autômatos? pois é eu dou aulas dessas coisas). Não é necessário ter FOR se você tem WHILE, não é necessário ter SWITCH se você tem IF. Não é necessário ter BOOLEAN se você tem INTEGER. Mas as linguagens tem para facilitar a vida do programador, reduzir a quantidade de erros semânticos no processo de compilação, ou seja, para ser mais fáceis e eficientes de serem usadas.

Passagem de argumentos por referência é um recurso extremamente poderoso, especialmente em uma linguagem que não trabalho com apontadores. Se alguém tem dúvidas quanto a isso consulte referência apropriada sobre paradigmas de programação na parte de programação imperativa. O livro do Sebesta é muito bom.

O que eu quero saber é por que uma característica tão útil e comum foi deixada de fora do projeto da linguagem. Qual é a justificativa da SUN para isso. Não como contornar o problema. Isso eu já sei.

Grato pela atenção de vocês e por qualquer indicação de documentação da SUN que possa esclarecer a dúvida.

Sds,
Prof. Jefferson O. Andrade, M.Sc.
CEFETES/UnED-Serra

Caríssimo prof. Jefferson:

em prmeiro lugar, desculpe pelo mal entendido, foi mal mesmo :slight_smile:

seguinte, achei alguns documentos no site da SUN, espero que sirvam de ajuda e que respondam a sua pergunta.

Se quiser dar uma olhada:

http://java.sun.com/products/jndi/tutorial/provider/ground/params.html