Java - Passaggio Valori

Java - Passaggio Valori
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"

  1. oggettini vari (penne, lampadine, libri)
  2. 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
.

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:

Giordano said...

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/