Posso passar parâmetros por referência em Java?

Respostas:

225

Java é confuso porque tudo é passado por valor . No entanto, para um parâmetro do tipo de referência (ou seja, não um parâmetro do tipo primitivo), é a própria referência que é passada por valor; portanto, parece ser passada por referência (e as pessoas costumam afirmar que é). Este não é o caso, como mostra o seguinte:

Object o = "Hello";
mutate(o)
System.out.println(o);

private void mutate(Object o) { o = "Goodbye"; } //NOT THE SAME o!

Irá imprimir Hellono console. As opções que você deseja que o código acima imprima Goodbyedevem usar uma referência explícita da seguinte maneira:

AtomicReference<Object> ref = new AtomicReference<Object>("Hello");
mutate(ref);
System.out.println(ref.get()); //Goodbye!

private void mutate(AtomicReference<Object> ref) { ref.set("Goodbye"); }
oxbow_lakes
fonte
48
Além disso, uma matriz de comprimento 1 pode ser usado para criar uma referência, se você realmente quer confundir as pessoas :)
Christoffer
2
AtomicReference e classes correspondentes (AtomicInteger) são os melhores para tais operações
Nav
3
AtomicReference é um exagero, você não necessariamente quer barreira de memória lá, e elas podem custar. O JRuby teve um problema de desempenho por causa de uma variável volátil usada ao construir um Objeto. A opção de usar a matriz como uma referência ad-hoc parece boa o suficiente para mim, e já a vi usada mais de uma vez.
Elazar Leibovich
Eu não acho que isso seja confuso, no entanto, esse é um comportamento normal. Existem tipos de valor na pilha e tipos de referência na pilha, mas também existem referências a tipos de referência na pilha. Assim, você sempre opera com o valor que está na pilha. Acredito que a pergunta aqui foi: É possível passar referência da pilha que aponta para algum outro valor que também esteja na pilha. Ou passa uma referência a outra referência que aponta para algum valor que vive na pilha?
eomeroff
isso eu ótima informação. Eu estava usando matrizes, mas isso parece algo construído para o trabalho. eu não sei sobre o desempenho desta matrizes vs. no entanto, se em um loop crítica desempenho
steveh
65

Posso passar parâmetros por referência em Java?

Não.

Por quê ? Java possui apenas um modo de passar argumentos para métodos: por valor.

Nota:

Para primitivos, isso é fácil de entender: você recebe uma cópia do valor.

Para todos os outros, você recebe uma cópia da referência e isso é chamado também de passagem por valor.

Está tudo nesta imagem:

insira a descrição da imagem aqui

PeterMmm
fonte
25

Em Java, não há nada no nível da linguagem semelhante ao ref . Em Java , apenas passa pelo valor semântico

Por uma questão de curiosidade, você pode implementar uma semântica semelhante a ref em Java, simplesmente agrupando seus objetos em uma classe mutável:

public class Ref<T> {

    private T value;

    public Ref(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }

    public void set(T anotherValue) {
        value = anotherValue;
    }

    @Override
    public String toString() {
        return value.toString();
    }

    @Override
    public boolean equals(Object obj) {
        return value.equals(obj);
    }

    @Override
    public int hashCode() {
        return value.hashCode();
    }
}

caso de teste:

public void changeRef(Ref<String> ref) {
    ref.set("bbb");
}

// ...
Ref<String> ref = new Ref<String>("aaa");
changeRef(ref);
System.out.println(ref); // prints "bbb"
dfa
fonte
Por que não usar java.lang.ref.Reference?
Codificado codificado 27/11/2009
java.lang.ref.Reference não tem um método set, não é mutável
dfa
por que não usar AtomicReference(para não-primitivos)? Ou AtomicSomething(por exemplo AtomicBoolean:) para primitivos?
Arvin #
Infelizmente, <T> não aceita tipos primitivos. Gostaria de fazer isso: Ref <int>
jk7
1
@ jk7 É realmente importante o suficiente ter que usar em intvez de Integer, em boolvez de Booleane assim por diante? Ou seja, as classes de wrapper (que são desembrulhadas automaticamente se você se preocupar com sintaxe) não funcionam?
Paul Stelian
18

De James Gosling em "A linguagem de programação Java":

"... Há exatamente um modo de passagem de parâmetro no Java - passagem por valor - e isso mantém as coisas simples."

duffymo
fonte
2
O pronunciamento do deus da língua deve ser declarado a resposta.
ingyhere
3
@ingyhere:: The pronouncement of the language god should be declared the answerNa verdade não. Apesar do que o criador do Java pensa ou acredita, a resposta absoluta viria de uma citação da especificação da linguagem.
paercebal
1
De fato, está no JLS, na seção 8.4.1 , e o JLS cita Gosling como primeiro autor: "Quando o método ou construtor é chamado (§15.12), os valores das expressões de argumento reais inicializam variáveis ​​de parâmetro recém-criadas , cada uma do tipo declarado, antes da execução do corpo do método ou construtor. "
ingyhere
Exatamente. O sarcasmo de membros de baixa representação não é útil.
Duffymo
11

Eu acho que você não pode. Sua melhor opção pode ser encapsular o que você deseja passar "por ref" para outra instância de classe e passar a referência da classe (externa) (por valor). Se você entende o que eu quero dizer ...

ou seja, seu método altera o estado interno do objeto ao qual é passado, que fica visível para o chamador.

Marc Gravell
fonte
7

Java é sempre transmitido por valor.

Quando você passa uma primitiva, é uma cópia do valor; quando você passa um objeto, é uma cópia do ponteiro de referência.

Nick Holt
fonte
4

Outra opção é usar uma matriz, por exemplo, void method(SomeClass[] v) { v[0] = ...; } mas 1) a matriz deve ser inicializada antes que o método seja chamado, 2) ainda não é possível implementar, por exemplo, o método swap dessa maneira ... Esse método é usado no JDK, por exemplo, em java.util.concurrent.atomic.AtomicMarkableReference.get(boolean[]).

Michal Misiak
fonte