Buono sconto 4% su Toner e Cartucce agli utenti AZpoint. SU Iomiricarico.it!!
- 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
allinterno di un metodo main
di unaltra 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 luna dallaltra.
Infatti, il valore della variabile unNumero,
sarà copiato nella variabile unAltroNumero.
Se il valore di una delle due variabili sarà successivamente
modificato, laltra variabile non apporterà modifiche al
proprio valore.
Invece, il reference unAltroGiorno,
semplicemente assumerà il valore (cioè lindirizzo)
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 alloggetto
comune, ovviamente questa sarà verificabile anche tramite
laltro 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.
|