questão complicada

em um teste de certificação, vi a seguinte questão:

class Value{
	public int i=15;
}
public class Test {
	public static void main(String argv[]){
		Test t = new Test();
		t.first();
	}
	public void first(){
		int i = 5;
		Value v = new Value();
		v.i = 25;
		second(v,i);
		System.out.println(v.i);
	}
	public void second(Value v,int i){
		i = 0;
		v.i = 20;
		Value val = new Value();
		v = val;
		System.out.println(v.i + " " + i);
	}
}

rodando esta aplicação, isto será impresso na tela:

15 0
20

o que eu não entendi, foi:

public void second(Value v,int i){
	i = 0;
	v.i = 20;
	Value val = new Value();
	v = val;
	System.out.println(v.i + " " + i);
}

Seguindo a execução:

  1. i recebe 0;
  2. v.i = 20;
  3. val é uma instância de Value;
  4. v recebe val;

Então, neste momento, v.i é igual a 15, pois recebeu o valor de val. Mas pq quando a execução do método second() acaba e volta pro método first(), v.i volta a ser 20, e nao continua sendo 15?

Porque a passagem de parametros em Java é sempre por valor, portanto, não adianta você modificar o valor da variavel v porque ela é só uma copia da variavel original passada por parametro… se você alterar o objeto, aí sim, vai modificar…

ex.:

[code]public class Value{
public int i = 15;
}

public void Teste(){
Value val = new Value();
val.i = 10;
alteraVariavel(val);
//val.i continua sendo 10
alteraObjeto(val);
//val.i foi modificado para 456
}

public void alteraVariavel(Value v){
v = new Value(); //nesse momento eu altero o valor de v, mas a variavel original passada por parametro continua intacta…
v.i = 123;
}

public void alterarObjeto(Value v){
v.i = 456; //apesar de nenhuma das variaveis terem sido alteradas, o objeto que elas referenciam foi, como o objeto é um só, vai mudar pra todas…
}[/code]

O que é mais importante você saber nisso tudo é que não existe passagem por referencia em Java, portanto, não dá pra alterar o valor da variavel original passada por parametro, como é possivel por exemplo em C.

então, isto está correto:

class Teste{
    int i = 5;
    String s = "teste";
}

public class Teste2{
    Teste t = new Teste();

    public void alteracoes(Teste te){
        te.s = "Julio";
        //alterou o valor original e, quando sair do método, o atributo s deste objeto continuará valendo "Julio"
        te = new Teste();
        te.s = "Segundo teste";
        //alterou o valor, somente dentro deste método
    }
}

isto está correto?

Eu acho que a forma mais facil de entender isso é assim:

Value v = new Value()

nesse ponto vc tem uma região de memoria (XXXX), essa regiao tem um objeto Value, e a variavel v tem a referencia para se chegar nesse endereço de memoria (ela guarda digamos o XXXX).

Ai vc faz isso

...
public sta void main(String[] args) {
  Value v = new Value()
  alt(v)
}
...
public void alt(Value val) {
  val.i = 99;
}
...

O parâmetro val recebe o conteudo de v, o conteudo de v eh a referencia para se chegar no objeto criado no main, ou seja como a variavel v guardava o endereço do objeto (XXXX), val tb vai guardar o mesmo endereço, logo quando vc fizer o val.i = 99, ele vai ver, val tah referenciando o objeto de que memoria? de XXXX , então ele vai alterar o objeto que estiver nessa região de memoria, que é o mesmo que v referencia, por isso essa alteração sera vista no main. Ai depois se vc fizer isso dentro do método alt:

alt(Value val) {
  val.i = 99;
  Value val2 = new Value();
  val = val2;
  val.i = 100;
}

Você esta criando outro objeto na memoria YYYY e fazendo uma variavel val2 referenciar esse endereço, depois diz que o conteúdo de val (que antes era XXXX) é o conteudo de val2, logo val não vai mais estar referenciando XXXX e sim YYYY, por isso que a alteração val.i = 100 não é vista por v no main, pois foi feita em outro objeto, um novo criado dentro do método, ja que agora val não esta mais referenciando XXXX e sim YYYY.

seila, tenta entender como as variaveis referenciam os objetos, ou melhor, o que as variaveis de objetos tem de conteudo, que são as referencias para objetos, para quem ja passou por um C da vida cheio dos ponteiros isso é facinho hehe faz uma tabela, e pensa que a cada new vc tah criando outra posicao de memoria, e que qualquer variavel que referencia o mesmo endereço, se vc alterar em uma vai alterar em outra.

valeu! :wink:

e sim, o que vc fez ali encima tah certo hehe

Uma coisa que não entendi mas entendi, foi o seguindo

Se v apontava para o Endereço XXXXXXXX
e agora ela aponta para o enderço YYYYYYYYY

como no metodo first ele ainda vai apontar para XXXXXXX ?

a referencia para a posição XXXX na memoria, ficou naquele objeto dentro do metodo first?
se a passagem é por referencia, alguma alteração no objeto v seja no valor dele ou para quem ele referencia num deveria alterar as coisas do v?

Fala Rafael! Uma coisa que você tem que tomar cuidado é a diferença entre as variáveis de referência e os objetos. As variáveis de referência são passadas como copias para os métodos. Essas copias apontam para o mesmo objeto, por isso se você modificar um atributo do objeto o qual essas variáveis referenciam (em qualquer umas das 2 ) ele vai ser modificado para ambas. Lembre-se existe apenas um objeto e 2 variáveis de referência. se pode exemplo o código abaixo for executado:


MyClass a = new MyClass();
a.i = 0;
MyClass b = a;
b.i = 1;
b = null;

O objeto ai não vai morrer porque uma das referências a ele agora referÊncia null, porém antes da variável de referência b apontar para null ela modificou o valor do objeto fazendo i agora valer 1

Lembra de uma coisa, variáveis de referência são passadas por copias assim como tipos primitivos, e essas cópias podem ambas referênciar um mesmo objeto. Um mesmo objeto pode ter N referências.

class Value{ public int i=15; } public class Test { public static void main(String argv[]){ Test t = new Test(); t.first(); } public void first(){ int i = 5; Value v = new Value(); v.i = 25; second(v,i); System.out.println(v.i); } public void second(Value v,int i){ i = 0; v.i = 20; Value val = new Value(); v = val; System.out.println(v.i + " " + i); } }

Entendi o que você me disse, mas tem uma pergunta sobre o código acima.

Se no metodo second, ele recebe uma referencia v, que aponta para o objeto, esse objeto inicialmente tem o valor de i = 20, blz?
ok, agora foi criado uma nova referencia, chamada val para um outro objeto, essa referencia tem o valor de i =15, blz?
ok, agora ele pega a v e faz receber val, isso num siginificaria que a referencia de v iria apontar para val? e com isso seria apresentado na tela o valor “15 0”, como resultado final do metodo second.

minha dúvida é, como a referencia v, agora aponta para o objeto a qual val também aponta, como é que no metodo first(), a referencia v ainda aponta para o primeiro objeto criado no metodo first() ?

obrigado pela ajuda.

Oi Rafael, mas o v do segundo metodo eh outra variavel, naum a mesma do v do primeiro, eh como se fosse assim:
Eu sou uma variavel, e a unica coisa que conheco eh o endereco de memoria de onde comeca o objeto, entao se eu vou alterar algo, altero o objeto, ai chamo um metodo que tem parametro, esse parametro eh vc! entao eu te digo: olha rafael, o endereco de memoria do objeto e tal!. Logo vc tb vai saber o endereco, e se vc alterar, vai alterar o mesmo objeto, mas depois vem alguem dentro desse metodo e te informa de outro endereco, ai vc vai alterar outro objeto, mas eu ainda estou aqui no metodo um, e lembro do endereco do primeiro.

Ex, inicia o metodo 1:
– Objeto1:
posicao de memoria: Y1
valor: o valor do objeto 1

– variavel v do metodo 1 :
posicao de memoria: X1
valor: Y1 (endereco de memoria do objeto 1)

Ai chamo o metodo dois passando a variavel v para um parametro que tb se chama v:
– parametro v:
posicao de memoria: X2 (eh outra variavel, tem outro endereco de memoria)
valor: Y1 (mesmo endereco de memoria do objeto 1)

Ai crio outra variavel val que recebe referencia para um novo objeto
– Objeto 2:
posicao de memoria: Y2
valor: o valor do objeto 2

– variavel val:
posicao de memoria: X3
valor: Y2

Ai faco v do parametro receber val, entao o v do parametro fica assim:
– variavel v do parametro:
posicao de memoria: X2 (eh outra variavel)
valor: Y2

Logo, v do parametro que esta na posicao de memoria X2, ao inves de apontar para o endereco de memoria Y1 que eh do objeto 1, agora aponta para o objeto Y2… mas la no meu metodo 1, ainda tenho uma variavel v que esta na posicao de memoria X1 que aponta para o objeto Y1. As variaveis estao em uma posicao de memoria, mas elas podem ter o mesmo valor (referencia para um objeto), quando faco:

v.i = 18

naum estou alterando o valor delas, e sim alguma coisa da referencia que ela esta apontando, mas qdo faco

v = val

ai sim altero o valor dela, fazendo ela apontar para outro objeto, mas altero apenas para essa variavel, e naum todas que apontam para o objeto

Entende?!

Entendi luBS,

Acho que o que eu confudia era que a variavel no parametro do metodo, eu pensava que ele era o proprio objeto a qual eu chamei.

Mas como esse parametro só aponta para o objeto que a outra variavel inicial também aponta, se eu mexer nela, tb mexe no objeto, mas como ela pode mudar e referenciar a outro objeto, sem mexer na referencia da primeira variavel.

Isos é tipico uma questão para confudir, pq normalmente a gente num faz algo desse jeito, e eu num percebia que o parametro na verdade é mais uma variavel que apontava para um objeto.

Vale lubs e a todos, to esclarecendo umas coisas para melhorar…

Obrigado.