G.Morreale
Introduzione:
Questo è un argomento base, ma spesso c'è parecchia confusione circa il passaggio dei valori in Java.
Proprio di recente ho letto un articolo http://www.javaranch.com/campfire/StoryCups.jsp
che tratta l'argomento attraverso delle similitudini, è proprio basandomi su tale testo che vorrei fare un pò di chiarezza a riguardo.
Supponiamo che le variabili siano dei cassetti di un mobile (Il mobile potrebbe essere paragonato all'heap)
I cassetti essenzialmente contengono due tipi di "cose"
- oggettini vari (penne, lampadine, libri)
- telecomandi (tipo quello della tv o dello stereo per intenderci)
Gli oggettini sarebbero i dati primitivi (byte, short, int, float, double).
Tali oggetti sono contenuti in cassetti di dimensione variabile, le penne infatti sono contenute dai cassetti grandi 15 cm2, mentre i libri sono contenuti da cassetti un pò più capienti allo stesso modo in cui i byte necessitano variabili da 8 bit mentre gli int necessitano 32 bit di spazio.
Quando viene chiamato un metodo passando un data primitivo, viene aperto ("allocato") un nuovo cassetto vuoto e all'interno viene copiato il dato(NON travasato).
Tale metodo si chiama "passaggio per valore".
I telecomandi invece sono contenuti in cassetti di ugual dimensione.
I telecomandi servono a comandare, come scrivevo prima tra parentesi, oggetti vari come la tv, lo stereo il dvd recorder etc. etc.
Bene, la tv, lo stereo etc. sono gli oggetti java (es. new Date()) e i telecomandi servono a "utilizzare" tali oggetti.
In questo caso quando viene chiamato un metodo e viene passato l'oggetto viene aperto("allocato") un nuovo cassetto e all'interno viene messa una copia del telecomando in grado di "comandare", "utilizzare" lo stesso oggetto del telecomando originale.
esempio:
public void foo(Date val)
{
/*val avrà una copia del riferimento(telecomando) in grado di gestire l'oggetto new Date() come avviene per now.*/
}
Date now = new Date();
foo(now);
Quindi si hanno due telecomandi differenti che gestiscono la stessa tv.
Modificando - val - non si andrà ad intaccare il riferimento di now e viceversa, però utlizzando attraverso val i metodi dell'oggetto Date si potrà modificare l'oggetto e anche now sarà al corrente di tali modifiche.
import java.util.Date;
public class Main
{
public static void main(String[] args)
{
Date now = new Date();
System.out.println("Now - prima di foo - " + now.toString());
Prova prova = new Prova();
prova.foo(now);
System.out.println("Now - dopo foo - " + now.toString());
}
}
class Prova
{
public void foo(Date val)
{
val.setTime(0);
val = null;
}
}
Quindi l'output del precedente esempio sarà
Now - prima di foo - Thu Oct 02 15:27:57 CEST 2008
Now - dopo foo - Thu Jan 01 01:00:00 CET 1970
Ciò dimostra che attraverso copie diverse dei telecomandi(riferimenti) si agisce sullo stesso oggetto.
All'interno di foo l'assegnamento
val = null
dimostra come i riferimenti siano stati passati per valore, quindi sono copie diverse.
now non può modificare il valore di val e viceversa ma entrambi possono modificare il valore dello stesso oggetto a cui puntano.
Oggetti Immutablii
Nel caso in cui gli oggetti trattati dai riferimenti(telecomandi) siano immutabili
Le classi Immutable sono read-only cioè non ci sono metodi SetField. I dati della classe sono definiti per sempre nel costruttore (e ovviamente sono privati). Esempio di classi Immutable sono String e Integer.
Si evitano così problemi di accesso concorrente ai dati della classe, poiché non ci sono metodi che modificano lo stato dell'oggetto dopo la sua creazione.
Si evitano così problemi di accesso concorrente ai dati della classe, poiché non ci sono metodi che modificano lo stato dell'oggetto dopo la sua creazione.
L'output del seguente esempio necessita di alcune considerazioni
public class Main
{
public static void main(String[] args)
{
String now = new String("ABC");
System.out.println("Prima di Foo " + now.toString());
Prova prova = new Prova();
prova.foo(now);
System.out.println("Dopo Foo " + now.toString());
}
}
class Prova
{
public void foo(String val)
{
val = val + "D";
val = null;
}
}
Nel momento in cui il valore now viene preso in considerazione dal metodo foo, val conterrà una copia del riferimento che punterà alla stringa "ABC", ma quando si eseguirà
val = val + "D";
essendo String un oggetto immutabile verrà creato un nuovo oggetto contenente "ABCD", val quindi punterà a tale oggetto e non più a quello vecchio.
Però essendo val una copia del riferimento di now, now non sarà modificato e quindi continuerà a puntare verso l'oggetto "ABC".
Quindi l'output del precedente esempio sarà
Prima di Foo ABC
Dopo Foo ABC
1 comment:
Che coincidenza, proprio stamattina ho letto un altro post che tratta lo stesso argomento
http://mariano.altervista.org/wordpress/2008/09/24/java-e-il-passaggio-di-parametri/
Post a Comment