PDA

View Full Version : [Java] Object a=b ...che succede?


luxorl
09-06-2009, 11:43
Ciao se creo due oggetti in java e poi faccio:

a=b;

Cosa succede? Copio il riferimento o duplico l'oggetto?
Da questo test che ho fatto:

public class test{

public static void main(String args[]){

Object x=new Object();
Object y=new Object();

//confronto se hanno lo stesso riferimento ---> NO
if(x==y) System.out.println("YES");
else System.out.println("NO");

System.out.println();

x=y;

//confronto se hanno lo stesso riferimento ---> SI
if(x==y) System.out.println("YES");
else System.out.println("NO");

System.out.println();

y="Yahoo";
x="AUGH";


System.out.println();
System.out.println(y);
System.out.println(x);

}

}

i due oggetti hanno lo stesso riferimento ma se modifico uno non tocco l'altro... mi chiarite le idee per favore? :)

!k-0t1c!
09-06-2009, 12:00
La questione è piuttosto semplice. Tu crei due oggetti e li assegni a due variabili. Il punto è che una variabile contiene un riferimento all'oggetto e se modifichi il valore della variabile non modifichi l'oggetto a cui punta, ma semplicemente sostituisci il riferimento. Quel che tu avevi in mente si vede invece con quest'esempio:

public class Foo
{
public Foo(int x) { Bar = x; }
public int Bar;
}

//...da qualche altra parte, ad es nel main
Foo x = new Foo(5);
Foo y = x;
x.Bar = 3;
System.out.println(y.Bar.toString());

Questo codice stampa 3 perché y ha un riferimento allo stesso oggetto a cui punta x ed è l'oggetto stesso (un suo field) a venire modificato.
Scrivendo

Foo x = new Foo(5);
Foo y = new Foo(5);
y.Bar = 3;
System.out.println(x.Bar.toString());
System.out.println(y.Bar.toString());

vedresti invece stampato prima 5 e poi 3 perché hai creato due oggetti diversi e ne hai modificato uno solo.
Infine se scrivi

Foo x = new Foo(5);
Foo y = x;
y = new Foo(4);
System.out.println(x.Bar.toString());

vedrai stampato 5 e non 4 perché tu hai semplicemente riassegnato y, ed y non *è* l'oggetto puntato da x ma *punta* a quell'oggetto quindi riassegnando y non cambi x né l'oggetto a cui x punta.
Per duplicare oggetti puoi usare .clone() laddove disponibile.

Axel-84
09-06-2009, 12:49
visto che sono anche un pò io il produttore della domanda, ti rilancio un'altro quesito.
Il problema nasce nel caso di oggetti dichiarati come Object


Object Ibuffer;
Object Sbuffer;

Object m = 4;

Ibuffer = m;

Sbuffer = Ibuffer; //l'oggetto viene duplicato???

Ibuffer = "test modifica";

System.out.println(Sbuffer + " --- " + Ibuffer);


in questo caso vengono stampati due valori diversi...
in particolare Sbuffer contiene 4 e Ibuffer contiene "test modifica"

è possibili che gli oggetti usati direttamente come Object abbiano un comportamento diverso da quello "standard"?

-------

Mi sono accorto, mentre scrivevo la domanda, dell'errore.

Scrivere Ibuffer = "test modifica";
equivale sostanzialmente a Ibuffer = new Object("test modifica");

luxorl
09-06-2009, 12:52
La questione è piuttosto semplice. Tu crei due oggetti e li assegni a due variabili. Il punto è che una variabile contiene un riferimento all'oggetto e se modifichi il valore della variabile non modifichi l'oggetto a cui punta, ma semplicemente sostituisci il riferimento.

In pratica il mio esempio non funziona perché facendo:

x="augh"

sostituisco NUOVAMENTE il riferimento della variabile facendolo puntare all'oggetto stringa "augh" ?

fero86
09-06-2009, 12:56
i due oggetti hanno lo stesso riferimento ma se modifico uno non tocco l'altro... mi chiarite le idee per favore? :) le stringhe in Java sono oggetti immutabili: quando riassegni "Yahoo" a y e "AUGH" a x non stai modificando il contenuto delle due stringhe, ma stai assegnando a x e y due nuovi oggetti stringa (anch'essi immutabili).

luxorl
09-06-2009, 13:01
le stringhe in Java sono oggetti immutabili: quando riassegni "Yahoo" a y e "AUGH" a x non stai modificando il contenuto delle due stringhe, ma stai assegnando a x e y due nuovi oggetti stringa (anch'essi immutabili).


In pratica il mio esempio non funziona perché facendo:

x="augh"

sostituisco NUOVAMENTE il riferimento della variabile facendolo puntare all'oggetto stringa "augh" ?

Giusto?

banryu79
09-06-2009, 13:09
public class test{

public static void main(String args[]){

Object x=new Object();
Object y=new Object();

Sono state create due reference, di tipo Object, di nome 'x' e 'y'.
'x' è stata fatta puntare a un nuovo Object, e 'y' è stata fatta puntare a un altro nuovo Object.

Notare quindi, che la parte a sinistra dell'assegnamento è la reference e la parte a destra dell'assegnamento è una istanza (un oggetto istanziato)


//confronto se hanno lo stesso riferimento ---> NO
if(x==y) System.out.println("YES");
else System.out.println("NO");

Qui si usa l'operatore di uguaglianza '==' che confronta istanze.
la reference 'x' punta a un'istanza di Object diversa da quella a cui punta la reference 'y'.


System.out.println();

x=y;

Qui c'è un assegnamento. Ricordando che la parte a sinistra è la reference a cui si assegna una istanza, la parte a destra viene risolta come l'istanza da assegnare.
In questo caso stiamo assegnando alla reference 'x' l'istanza puntata dalla reference 'y'. La vecchia istanza di Object puntata da 'x' resta così senza riferimenti, e, siccome parliamo di Java, diventa eleggibile per essere garbage-collected.



//confronto se hanno lo stesso riferimento ---> SI
if(x==y) System.out.println("YES");
else System.out.println("NO");

System.out.println();

Chiaramente ora sia 'x' che 'y' puntano alla stessa istanza, quindi si verifica l'uguaglianza.


y="Yahoo";
x="AUGH";

La reference 'x' viene nuovamente fatta puntare a una nuova istanza. In questo caso si sta assegnado un letterale di tipo String.
Anche la a reference 'y' viene fatta puntare a una nuova istanza. Anche in questo caso si sta assegnado un letterale di tipo String, diverso dal precedente. Parliamo quindi della creazione di due istanze diverse di tipo String.
La vecchia istanza di Object puntata da 'x' e 'y' resta ora senza riferimenti diventando in teoria eleggibile per essere garbage-collected.


System.out.println();
System.out.println(y);
System.out.println(x);

}

}

Qui vengono stampate le due istanze di tipo String create al passaggio precedente. Prima viene stampata l'istanza puntata da 'y', poi quella da 'x'.

!k-0t1c!
09-06-2009, 13:41
Tutto il problema sta nella confusione tra una variabile che punta ad un oggetto e l'oggetto stesso. La variabile è un po' come un puntatore in C, io posso riassegnarlo e puntare a qualcos'altro senza cambiare il contenuto della memoria a cui puntava precedentemente. Quanto alla domanda ricorrente "l'oggetto viene duplicato" la risposta è semplicemente *NO*. Solo implementando funzioni specifiche (vd. clone) un oggetto può venire duplicato, diversamente è sempre lo stesso riferimento che viene passato in giro per variabili ed argomenti.

banryu79
09-06-2009, 14:13
Usando una terminologia "Javista" più precisa, si parla di reference/riferimenti e istanze di oggetto.
Tenuta da conto questa distinzione, e il fatto che il passaggio dei parametri avviene sempre per valore [passaggio per valore di un tipo primitivo oppure passaggio per valore di un riferimento] quando si legge un sorgente non dovrebbero esserci più problemi/confusioni di sorta.
E sì, le references in Java sono simili ai puntatori in C (solo non è possibile l'aritmetica dei puntatori).

!k-0t1c!
09-06-2009, 14:37
Visto che sei entrato nel tema del passaggio dei parametri, che in Java come in C# è di default per valore e non per riferimento, posto questo link che credo possa chiarire qualche dubbio ai neofiti (a loro agio con l'Inglese): http://www.yoda.arachsys.com/java/passing.html

wingman87
09-06-2009, 14:42
Giusto?