Em Java toda a passagem é por referência, mito ou verdade?

15 respostas
renzonuccitelli

Outro dia um amigo meu me perguntou se a passagem de parametro em Java é feita por referência. Respondi prontamente que sim, como já havia escutado várias vezes de muitas pessoas. Então ele colocou o seguinte código pra rodar:

public class Cobaia {
	private int id;

	public int getId() {
		return id;
	}

	public Cobaia(int id) {
		super();
		this.id = id;
	}

	public void setId(int id) {
		this.id = id;
	}
}
public class Mito {
	public void alterarCobaiaCriandoNova(Cobaia cobaia){
		cobaia=new Cobaia(0);
	}
	public void alterarCobaiaPassandoReferencia(Cobaia cobaia){
		Cobaia c=new Cobaia(0);
		cobaia=c;
	}
	
	public void alterarCobaiaUsandoMetodo(Cobaia cobaia){
		cobaia.setId(0);
	}
}
public class MitoTeste {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Cobaia cobaia=new Cobaia(1);
		Mito mito=new Mito();
		mito.alterarCobaiaCriandoNova(cobaia);
		System.out.println(cobaia.getId());
		mito.alterarCobaiaPassandoReferencia(cobaia);
		System.out.println(cobaia.getId());
		mito.alterarCobaiaUsandoMetodo(cobaia);
		System.out.println(cobaia.getId());

	}

}

Para minha supresa e a dele, o resultado impresse foi 1 1 0. Assim, se a passagem fosse mesmo feita por referência, nós o resultado a ser impresso deveria ser 0 0 0. Assim, chegamo a conclusão que o que dizem não é correto. A passagem seria feita por valor, e os métodos do objeto em si seriam passados como referência. Mas gostaria de saber do pessoal que manja de Java pudesse dar uma explicação melhor para isso, se possível.

15 Respostas

Valder_Olmo_Correa

renzonuccitelli, sempre ouvi dizer que a passagem de parâmetros em java é sempre por valor, pois não há passagem por referência em Java.
Sempre pensei também que em C houvesse passagem por referência, mas não há, o que o C faz é passar um ponteiro para que a variável apontada pelo ponteiro seja modificada.

renzonuccitelli

Sim, mas isso de passar o ponteiro é que faz ser a passagem por ref, o ponteiro é a referência, ou seja, qdo vc mudar o valor do argumento, mudará o valor da variaável que foi passada.
Te digo que sempre ouvi que a passagem em Java era feita por ref e nao por valor…

dm_thiago

A passagem de objetos é SIM feita por referência.

renzonuccitelli:
public class Mito {
	public void alterarCobaiaCriandoNova(Cobaia cobaia){
		cobaia=new Cobaia(0);
	}
	public void alterarCobaiaPassandoReferencia(Cobaia cobaia){
		Cobaia c=new Cobaia(0);
		cobaia=c;
	}
	
	public void alterarCobaiaUsandoMetodo(Cobaia cobaia){
		cobaia.setId(0);
	}
}
public class MitoTeste {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Cobaia cobaia=new Cobaia(1);
		Mito mito=new Mito();
		mito.alterarCobaiaCriandoNova(cobaia);
		System.out.println(cobaia.getId());
		mito.alterarCobaiaPassandoReferencia(cobaia);
		System.out.println(cobaia.getId());
		mito.alterarCobaiaUsandoMetodo(cobaia);
		System.out.println(cobaia.getId());

	}

}

No seu método main você criou um objeto Cobaia e o atribuiu a variável cobaia, ou seja, a variável cobaia agora aponta para o endereço do objeto que você acabou de criar.

Quando você chama um método e passa um objeto como parâmetro, você passa o endereço dele para o método. Então quando você chamou o método alterarCobaiaCriandoNova, a sua variavel cobaia (na assinatura do método) recebeu o endereço do objeto que você havia criado no metodo main. Então agora você tem duas variáveis apontando para o mesmo objeto, a do método main e aquela do seu método alterarCobaiaCriandoNova.

Caso você faça alguma alteração NO OBJETO (acessando diretamente os atributos ou usando métodos de acesso), você verá que não importa qual variável você use para imprimir o valor, ambas irão mostrar o mesmo valor. Agora, quando você criar um novo objeto, e atribuí-lo a uma variável, você só mudou o endereço para onde aquela variável apontava, e não sobrescreveu o objeto que era apontado pela variável. Então, se antes as duas variáveis apontavam para o mesmo objeto, agora uma irá apontar para um e a outra para o outro.

Um exemplo real de como isso funcionaria:

1) Pense que o seu dedo é uma variável, que pode apontar para qualquer coisa (seria como um "Object dedo;")
2) Agora aponte para uma tomada (Atribuimos um objeto para a variavel dedo, no java seria um "dedo = new Tomada();")
3) Agora pegue o dedo do seu amigo e aponte para a mesma tomada ("Object dedoAmigo = dedo;")
4) Agora, pinte você a tomada de branco ("dedo.setColor(Color.WHITE);")
5) Veja, a tomada para a qual você e seu amigo estão apontando agora é branca!
6) Agora mande seu amigo pintá-la de vermelho ("dedoAmigo.setColor(Color.RED);")
7) E agora, vocês dois estão apontando para uma tomada vermelha.
8) Para completar a simulação, você agora aponte para uma outra tomada ("dedo = new Tomada();")
9) Agora pinte a tomada que você está apontando de azul ("dedo.setColor(Color.BLUE);")

Repare, seu amigo continua a apontar aquela antiga tomada, que está vermelha, e você agora aponta uma tomada azul. Vocês deixaram de possuir a mesma referencia quando você criou uma nova tomada para você (no passo 8).

Entendeu o que aconteceu no seu programa de teste? A partir do momento que você criou novos objetos, você perdeu a antiga referencia, que tinha sido criada no metodo main, então a variável do seu método main continuou apontando para a variável antiga, e não a que você criou nos métodos.

E é assim que funciona a passagem por referência. Espero ter sido claro ;)

thegoergen

Perfeito dm_thiago.

Realmente agora eu consegui entender, estava quebrando a cabeça interpretando o código da Cobaia e do Mito. :lol:

Na verdade, eu nunca tinha parado pra pensar sobre o assunto…

jingle

realmente… muito bom exemplo, não deixa brecha para duvidas. :smiley:

lcegatti

Muito bom mesmo dm_thiago, mando bem nessa.

[]'s

wagnerfrancisco

Se não me engano, segundo o Head First: Java, a passagem é feita SEMPRE por VALOR.

Ou seja, tu envia uma cópia do conteúdo da tua “variável”. No caso de primitivos, tranquilo. É fácil observar, já que o valor não é alterado no método que recebe o valor por parâmetro. No caso de objetos, a confusão acontece porque o conteúdo da variável não é a instância do objeto, e sim o endereço desta instância. Quando você manda um objeto por parâmetro, você passa o conteúdo dele (por valor, cópia). Só que o conteúdo é o endereço. Desse modo, você cria uma outra variável que recebe o mesmo endereço. Concluindo, a cópia é por valor.

Falou.

rafaelglauber

Oi,

Vejo que todo mundo gostou da explicação, não concordo com ela e a sun também não, logo se alguém tá pensando em fazer certificação java nunca respondam isso, toda passagem é por valor e não por referência ou qualquer outra coisa. A diferença quando tratamos de objetos é que a cópia não é do objeto, mas sim da referência ao objeto.

ps. não estou dizendo que a explicação não é correta, ou que não foi boa, só não tá de acordo com as documentações da sun e dos materiais de certificação.

renzonuccitelli

Rafael, sua explicação sobre a cópia da referência fica melhor mesmo. Porque a outra tb não gostei não não. Em C, se vc recebe o valor por referência (o ponteiro) e vc apota ele para outro lugar, o valor que vc tinha passado muda tb, o q não aconteceu com o exemplo. Sendo a cópia da refêrencia, aí sim, fica explicado o funcionamento…
Vlw galera, vivendo e aprendendo…hehe

souzaJr

dm_thiago,

você não passa o endereço do objeto para o método, o que é passado é uma cópia (valor) do endereço (referência), e é por isso que é comum dizer que toda passagem de parametros em Java é sempre por valor (seja por valor de referência - para objetos, ou valor mesmo - tipo primitivo).

Assim, você pode alterar o estado (atributos) do objeto para qual a referência (a cópia) adquirida pelo método aponta, mas não a própria referência. Você fica com duas referência e um só objeto…

É por isso que isso acontece…porque você não pode alterar a referência do seu colega…pq você não a tem…você só tem a cópia…e faz o que quiser com ela (Pode apontar para onde quiser).

Até mais.

Andre_Brito

Essa discussão nunca acaba. Já teve alguma coisa parecida aqui eu acho. Apesar disso, é uma coisa muito importante. Até me lembro de uma coisa que acontece em meados de Fevereiro. Eu estava (ainda estou) em um projeto de um AG Hibridizado Fuzzy. Temos, mais ou menos, míseras 20, 30 classes e estão bastante acopladas. O resultado final não era confiável porque ele foi feito em partes (um faz um, outro faz outra parte) e nos deparamos justamente com esse problema: chamávamos um método e mudávamos o valor do parâmetro. Quando fomos debuggar, BUM! Tudo estava mudando mesmo… até que tivemos que fazer um clone() em muitas classes. Aprendemos com as “cagadas” que estavam acontecendo. Porém, em algumas situações, utilizar e mudar o parâmetro parece que não acarreta em outro erros semânticos… sei lá hein… essa questão, por mais que muito discutida, ainda não bate bem.

lcegatti

rsrs verdade

Enfim … isso acabou com minhas dúvidas sobre o assunto, talvez ajude.

[]'s

s4nchez

Aqui tem outro artigo explicando como java funciona:

http://www.javaranch.com/campfire/StoryPassBy.jsp

Marcio_Duran

Exite tipos de referência, os quais incluem recursos que permitem a manipulação de objetos e matrizes(arrys) em uma única variável.

Todos os dados manipulados em java fazem parte de alguma classe, com exceção dos dados primitivos da linguagem (int, long, float, double, boolean, char etc…)

Outro ponto é que a instância de classe(ou seja, objeto) criada é sempre manipulada por meio de algo que a referencie - no caso, as variáveis declaradas no programa.Para isso, essas variáveis se utilizam de possibilidade de fazer referência usando o endereço da instância.Esse endereço é atribuído a alguma variável declarada, que passa a apontar para a instancia.

String str = new String("Marcio Duran");
renzonuccitelli

Desenterrou…hehe

Criado 4 de outubro de 2008
Ultima resposta 19 de jan. de 2009
Respostas 15
Participantes 12