Cosa succede quando si fa p=q oppure p==q?
Come si copiano/confrontano gli oggetti?
Come vengono passati gli oggetti ai metodi?
int x; Point p;
Per ogni variabile esiste una casellina (spazio di memoria)
Non c'è nessuna differenza! (finora)
La espressione new Point() crea un oggetto e restituisce l'indirizzo di memoria dell'oggetto.
Effetto di new Point():
new Point() è un metodo;
il valore restituito è la posizione dell'oggetto
creato in memoria.
p=new Point();
Significa: l'indirizzo di memoria in cui si trova l'oggetto creato va in p
Finora abbiamo visto la memoria come una lavagna.
In realtà la memoria è come una fila di cassetti numerati:
In ogni cassetto posso metterci un dato
Posso fare operazioni del tipo: metti un dato in un cassetto 32, vedi cosa c'è nel cassetto 9, ecc.
Per accedere a un cassetto (per metterci qualcosa o per vedere cosa c'è) devo specificare il numero
Il numero del cassetto si chiama indirizzo.
Il cassetto numerato 5 (indirizzo 5) contiene il valore 24.
I cassetti hanno tutti indirizzi diversi (non ci sono due cassetti numero 5)
Due cassetti possono contenere lo stesso dato (per esempio, 24 sta sia in 54 che in 1)
Nella realtà: quasi tutte le variabili e gli oggetti sono spezzati in più cassetti.
Per noi: facciamo finta che ogni variabile e ogni oggetto sta in un cassetto.
Per le variabili scalari (interi, ecc) non ha importanza.
Le variabili oggetto contengono un numero, che è l'indirizzo della cella in cui si trova l'oggetto.
Questo ha importanza quando si copiano oggetti, si confrontano, si passano come parametri, ecc.
Quando si fa p=new Point();:
Vediamo la memoria un passo per volta.
int x; Point p;
A ogni variabile viene assegnato un cassetto:
In questo esempio, la variabile x è il cassetto numero 1
È lui a scegliere quali cassetti associare alle variabili!
La seconda volta che si esegue il programma, la variabile x potrebbe essere associata al cassetto 29
Voi sapete solo che ogni volta che usate x oppure p, viene usato il cassetto giusto.
x=-131;
Assegnare un valore=mettere il valore nel cassetto associato all variabile.
new Point();
L'oggetto viene messo in un cassetto.
Il metodo new Point() restituisce un numero:
il costruttore restituisce l'indirizzo (numero di indice della cella) in cui si trova l'oggetto creato
In questo caso, viene restituito il valore 5
Quando faccio p=, l'indirizzo dell'oggetto va in p
In p viene messo 5 perchè l'oggetto creato si trova nel cassetto 5.
Sulla lavagna lo scrivo:
Ricordate che significa: nella variabile p c'è il numero della cella in cui si trova l'oggetto.
Le variabili si comportano tutte nello stesso modo.
Non c'è nessuna differenza fra una variabile intera e una variabile oggetto, a parte il tipo
int y; Point q; y=x; q=p;
Cosa succede?
Il valore di una variabile è il numero scritto nel suo cassetto.
Quindi, il valore di x è -131
Il valore di p è 5!
y=x; q=p;
I valori (contenuto delle celle) di x e p vengono copiati (nelle celle) y e q
Le due variabili contengono una freccia verso lo stesso oggetto.
La freccia dice che in una variabile c'è l'indirizzo di una posizione di memoria.
Se due freccie puntano nello stesso punto, allora i due valori sono gli stessi.
x=10; y=x; y=-5; System.out.println(x);
Quando faccio y=x significa solo che in y viene copiato il valore di x
Quando faccio y=-5 il valore di x resta inalterato.
Viene stampato 10
p.x=10; q=p; q.x=4; System.out.println(p.x);
È praticamente lo stesso programma di prima.
Succedono le stesse cose di prima, però gli effetti sono completamente diversi.
Dopo q=p, l'indirizzo dell'oggetto viene scritto anche in q
Poi faccio q.x=4;
Ma l'oggetto il cui indirizzo sta in q
è sempre quello!
Stampare p.x causa la stampa di 4
Sembra che siano state fatte le stesse cose:
var=valore; altravar=var; altravar=nuovo_valore;
Solo che per interi var non cambia, mentre per gli oggetti si
In realtà, anche sugli oggetti succede la stessa cosa.
Non è una eccezione sugli oggetti.
È una conseguenza del principio generale: nelle variabili c'è l'indirizzo di un oggetto (un numero)
Poi le variabili oggetto si comportano nello stesso modo.
q=p copia l'indirizzo dell'oggetto, non copia l'oggetto
Gli oggetti si possono copiare, ma non facendo q=p
Modo giusto: creo un nuovo oggetto e ci metto dentro i valori dell'altro
Point q; q=new Point(); q.x=p.x; q.y=p.y;
In memoria, viene creato un nuovo oggetto.
Quando faccio q.x=p.x viene copiato il valore nel nuovo oggetto.
Se ora faccio q.x=4, viene modificato solo il secondo oggetto!
Cosa viene stampato?
Point p; p=new Point(); p.move(10,20); Point q; q=new Point(); q.move(-2,-2); q=p; p.x=4; System.out.println(q.x);
Quando il meccanismo dei puntatori sarà chiaro,
non saranno necessarie le figure.
Per ora invece servono.
Regola generale: assegnare = copiare il valore
Nel caso delle variabili per oggetti, il valore è l'indirizzo.
Viene creato un oggetto, il cui riferimento (indirizzo di memoria) va in p
p.move modifica i campi dell'oggetto il cui riferimento sta in p
I metodi lavorano sull'oggetto dato il suo riferimento
Stessa cosa: creo un oggetto, metto il riferimento in q, invoco il metodo.
Faccio l'assegnamento q=p
Quello che è successo: il numero scritto in p è stato copiato in q
È la stessa cosa che viene fatta quando si fa x=y con due variabili intere.
p.x=4;
La variabile p.x viene modificata.
Quanto vale q.x?
È la componente x dell'oggetto il cui indirizzo sta in q
Quindi, è sempre 4
Non c'è più nessuna variabile che contiene l'indirizzo del secondo oggetto.
Il secondo oggetto non si può più usare.
L'oggetto viene cancellato in modo automatico.
Point t; t=q; q=s;
In questo caso, ottengo questo stato della memoria:
Posso ancora usare il secondo oggetto, dato che il suo indirizzo sta in t
Quando si lavora con oggetti, le variabili contengono numeri (indirizzi).
Le variabili si comportano come variabili intere.
Per evitare di scrivere dei numeri a caso, uso le freccie. Ma è solo un modo semplificato.
Copio i valori.
Questo equivale a ``copiare le freccie''
q=p mette in q una freccia che va nello stesso punto della freccia di p
Da adesso in poi, facciamo tutte le figure con le freccie.
Ricordate che si tratta solo di un modo per rappresentare indirizzi.
class Segmento { Point inizio; Point fine; }
Sia dato questo programma:
Segmento s, r; s=new Segmento(); r=s;
Si può fare?
L'unico vincolo è che non posso usare gli oggetti fino a che non li ho creati.
Ma posso usare s anche se s.inizio ed s.fine non sono stati creati.
Posso memorizzare un valore in r anche se non ho creato l'oggetto.
Non posso fare r.inizio=... prima di aver fatto r=s soltanto perchè non esiste l'oggetto puntato da r
Segmento s, r; s=new Segmento(); s.inizio=new Point(); s.inizio.x=12; r=new Segmento(); r.inizio=s.inizio; s.inizio.x=-4; System.out.println(r.inizio.x);
Cosa viene stampato?
Fare la figura con lo stato della memoria
Stato dopo la creazione di s ed r
Scrivo i nomi delle classi su ogni oggetto
Per ora, ci serve a non fare confusione.
Poi si vedrà che serve.
Vale la solita regola: il valore della variabile viene copiato.
Ma s.inizio indica un oggetto, quindi la variabile contiene un riferimento.
Il riferimento viene copiato.
s.inizio.x ed r.inizio.x sono la stessa cosa.
Viene stampato -4
int x, y; Point p, q; ... if(x==y) ... if(p==q) ...
È sempre la stessa cosa!
p==q non dice se l'oggetto p è uguale all'oggetto q!
Point p, q; p=new Point(); p.move(10,10); q=new Point(); q.move(10,10); if(p==q) System.out.println("Sono uguali"); else System.out.println("Non sono uguali");
Cosa viene stampato?
Dato che i due punti sono uguali,
la condizione p==q è vera.
Cosa succede in memoria?
Dopo aver creato i due oggetti:
Ogni volta che faccio new, ho un nuovo oggetto, in una nuova posizione.
Sono due oggetti diversi, per cui le loro posizioni in memoria sono diverse!
Il contenuto di p e di q è lo stesso?
p contiene 5 mentre q contiene 7.
Sono diversi.
q=p; if(q==p) ...
Ora p e q contengono lo stesso valore.
p==q è vera se e solo se le freccie di p e di q vanno nello stesso punto:
Basta guardare i valori:
Point p, q; p.move(10,10); q.move(10,10); if((p.x==q.x) && (p.y==q.y)) ...
Attenzione agli oggetti con dentro altri oggetti!
(non va fatto il confronto fra due variabili oggetto
anche se stanno dentro un altro oggetto)
Su alcuni tipi, è definito il metodo equals che confronta gli oggetti, non gli indirizzi.
Point p, q; p.move(10,10); q.move(10,10); if(p.equals(q)) ...
Definire un metodo uguale che confronta due oggetti NumeroComplesso
class NumeroComplesso { double reale; double imm; }
Mettere il metodo dentro la classe.
Ha un oggetto di invocazione; l'altro oggetto va passato.
Restituisce un boolean.
boolean uguale(NumeroComplesso n) { ... }
Ritorno true solo se i due numeri sono uguali.
boolean uguale(NumeroComplesso n) { return ((this.reale==n.reale) && (this.imm==n.imm)); }
Fra dati scalari (interi, ecc) il confronto con == confronta il valore!
Su tutti gli oggetti è definito un metodo equals
Fa cose diverse a seconda della classe:
Point p, q; p=new Point(); p.move(10,20); q=new Point(); q.move(10,20);
Qui p.equals(q) vale true
Studente s, t; s=new Studente(); s.nome="Paolo"; s.media=19; t=new Studente(); t.nome="Paolo"; t.media=19;
Qui s.equals(t) è false
Vedremo in dettaglio l'ereditarietà, e poi come è definito esattamente il metodo equals
Per ora: se voglio aggiungere un metodo di confronto fra oggetti in una classe, lo chiamo uguale invece di equals
Le variabili oggetto contengono il riferimento all'oggetto.
Vale anche per le stringhe.
Quando una stringa costante, tipo "abcd" appare due volte in un programma, è lo stesso oggetto
String s, q; s="abcd"; q="abcd"; System.out.println(s==q)
Viene stampato true
Quando appare due volta la stessa stringa costante, viene usato lo stesso oggetto.
In questo caso, s==t ritorna true
NO
s="abcd"; q="abcd"; System.out.println(s==q); String a, b; a="ab"; b="cd"; String t=a.concat(b); System.out.println(s==t); System.out.println(q==t);
Stato della memoria:
Questo discorso dello stesso oggetto
vale solo per le stringhe costanti.
(quelle scritte con "...")
Dipende da cosa fa equals:
Nel secondo caso, si può definire un metodo uguale che confronto i valori numerici.
Quando si invoca un metodo, i parametri attuali vengono copiati nei parametri formali.
Questo è un assegnamento come quelli visti finora.
Segue le regole dell'asegnamento:
se il parametro formale è un
intero, si copia l'intero;
se è un
oggetto, si copia il riferimento.
Conseguenze: altra lezione.