Tipi di dati non primitivi: reference

Abbiamo già visto come istanziare oggetti da una certa classe. Dobbiamo prima dichiarare un oggetto di tale classe con una sintassi di questo tipo:

NomeClasse nomeOggetto;

per poi istanziarlo utilizzando la parola chiave new. Dichiarare un oggetto quindi è del tutto simile a dichiarare un tipo di dato primitivo. Il "nome" che diamo ad un oggetto è detto "reference". Infatti, non si sta parlando di una variabile tradizionale bensì di un puntatore. Possiamo definire un puntatore come una variabile che contiene un indirizzo in memoria. C’è una sottile e potente differenza tra la dichiarazione di un tipo di dato primitivo ed uno non primitivo. Consideriamo ora un esempio, partendo dalla definizione di una classe che astrae in maniera banale il concetto di data.

 

class Data

{

    int giorno;

    int mese;

    int anno;

}

 

Data sarà quindi un tipo di dato non primitivo (astratto) per il nostro esempio. Come tipo di dato primitivo consideriamo un double. Consideriamo le seguenti righe di codice, supponendo che si trovino all’interno di un metodo main di un’altra classe:

 

double unNumero=5.0;

    Data unGiorno=new Data();

 

Graficamente potremmo immaginare la situazione in memoria con questo tipo di schematizzazione:

 

La differenza pratica tra un reference ed una variabile, è evidente nelle assegnazioni. Consideriamo il seguente frammento di codice:

 

double unNumero=5.0;

    double unAltroNumero=unNumero;

    Data unGiorno=new Data();

    Data unAltroGiorno=unGiorno;

 

La variabile unAltroNumero, assumerà lo stesso valore della variabile unNumero, ma, le due variabili, rimarranno indipendenti l’una dall’altra. Infatti, il valore della variabile unNumero, sarà copiato nella variabile unAltroNumero. Se il valore di una delle due variabili sarà successivamente modificato, l’altra variabile non apporterà modifiche al proprio valore.

Invece, il reference unAltroGiorno, semplicemente assumerà il valore (cioè l’indirizzo) del reference unGiorno. Ciò significa che unAltroGiorno punterà allo stesso oggetto cui punta unGiorno. Ecco la situazione rappresentata graficamente:

Quindi, se successivamente sarà apportata una qualche modifica tramite uno dei due reference all’oggetto comune, ovviamente questa sarà verificabile anche tramite l’altro reference. Per intenderci:

unGiorno.anno

è sicuramente equivalente a:

unAltroGiorno.anno

 - Passaggio di parametri per valore

Come abbiamo già accennato nel precedente capitolo il passaggio di parametri in Java avviene sempre per valore. Ciò significa che quando viene invocato un metodo che come parametro prende in input una variabile, al metodo stesso viene passato solo il valore (una copia) della variabile, che quindi rimane immutata anche dopo l'esecuzione del metodo. Per esempio consideriamo la classe:

 

class CiProvo

        {

        public void cambiaValore(int valore)

        {

            valore = 1000;

        }

        }

 

il seguente frammento di codice:

 

CiProvo ogg = new CiProvo();

    int numero = 10;

    ogg.cambiaValore(numero);

    System.out.println(“il valore del numero è ” + numero);

 

produrrà il seguente output:

    il valore del numero è 10

Infatti il parametro valore del metodo cambiaValore(), nel momento in cui è stato eseguito il metodo, non coincideva con la variabile numero, bensì immagazzinava solo la copia del suo valore (10). Quindi ovviamente la variabile numero non è stata modificata.

Stesso discorso vale per i tipi reference: viene sempre passato il valore del reference, ovvero, l'indirizzo in memoria. Per esempio consideriamo la seguente classe:

 

class CiProvoConIReference

        {

        public void cambiaReference(Data data)

        {

        data = new Data(); // Un oggetto appena istanziato

        // ha le variabili con valori nulli

        }

        }

 

il seguente frammento di codice:

 

CiProvoConIReference ogg = new CiProvoConIReference();

    Data dataDiNascita = new Data();

    dataDiNascita.giorno = 26;

    dataDiNascita.mese = 1;

    dataDiNascita.anno = 1974;

    ogg.cambiaReference(dataDiNascita);

    System.out.println(“Data di nascita = ” + dataDiNascita.giorno

+ “-”+ dataDiNascita.mese + “-” +dataDiNascita.anno );

 

produrrà il seguente output:

    Data di nascita = 26-1-1974

Quindi valgono le stesse regole anche per i reference.

N.B.: Attenzione che se il metodo cambiaReference() avesse cambiato i valori delle variabili d'istanza dell'oggetto avremmo avuto un output differente. Riscriviamo il metodo in questione:

 

public void cambiaReference(Data data)

    {

        data.giorno=29; // data punta allo stesso indirizzo

        data.mese=7 // della variabile dataDiNascita

    }

 

Il fatto che il passaggio avvenga sempre per valore, garantisce che un oggetto possa essere modificato, e contemporaneamente, si è certi che dopo la chiamata del metodo il reference punti sempre allo stesso oggetto.

N.B.: altri linguaggi come il C, permettono anche il passaggio di parametri “per riferimento”. In quel caso al metodo viene passato l'intero riferimento, non solo il suo indirizzo, con la conseguente possibilità di poter mutarne l'indirizzamento. Java ha scelto ancora una volta la strada della robustezza e della semplicità, favorendola alla potenza del linguaggio.

 



Ti potrebbe interessare anche

commenta la notizia

C'è 1 commento
Francesco
Hai dubbi su questo articolo?