PDA

View Full Version : attenzione!!!


speedwago
23-02-2004, 03:23
sul discorso passaggio valore/riferimento .....non e' che con i primitivi il passaggio e' per rifermento mentre con gli oggetti il passaggio e' x riferimento... il passaggio è sempre e solo per riferimento!!

il problema e' che gli operatori si comportano in modo da indurti a credere a questo!!!
praticamente nella jvm (potete consultare la specifica). interi, double e String sono gli unici tipi ad essere assegnati tramite literal e per questo considerati oggetti costanti (non modificabili)!!
vi e' quindi un constant string pool , un cosatant double pool ecc ecc ecc...
gli operatori + - ecc ecc ecc funzionano in modo da creare una nuova isntanza dell'oggetto.
quindi se faccio i+1 o i++ io vado a a creare un nuovo intero costante, e lo assegno al riferimento ma non vado a modificare il riferimento!!
Infatti se fate il giochetto che avete fatto con l'intero che passa da 20 a 30 con un oggetto di tipo String succede la stessa cosa!!!!
praticamente x oggetti che non hanno il costruttorel'operatore = funziona come operator new... nel caso del metodo che cambiia il valore dell 'intero da 20 a 30


public void eseguiEsperimento() {
int intero = 10;
System.out.println("prima del passaggio");
System.out.println(intero);
System.out.println("dopo il passaggio");
passaggioPerValore(intero);
System.out.println(intero);
}

public void passaggioPerValore(int primitivo) {
primitivo = 20;
}


esso crea un varbl nello scope di passaggioPerValore che ha lo stesso nome di intero ma non è intero!

bizzu
23-02-2004, 12:39
Quindi se ho capito bene l'ultimo System.out.println(intero) scrive 20?

Non ho capito questa frase però:
esso crea un varbl nello scope di passaggioPerValore che ha lo stesso nome di intero ma non è intero!
Che fine fa la variabile creata nello scope della funzione? Rispetto a quanto hai detto prima, intero dovrebbe "puntare" a questa, ma essendo solo nello scope della funzione, la variabile non dovrebbe essere distrutta?
Forse ho fatto un po' di confusione...
Chiaritemi 'sto dubbio che dopodomani devo presentare una relazione sulla JVM ... :(

recoil
23-02-2004, 12:48
Originariamente inviato da bizzu
Quindi se ho capito bene l'ultimo System.out.println(intero) scrive 20?

no
l'altro giorno ho pure fatto una prova per togliermi definitivamente il dubbio.

non commento il resto del messaggio originale perché prima dovrei leggere bene le specifiche della VM

bizzu
23-02-2004, 14:02
Originariamente inviato da recoil
no
l'altro giorno ho pure fatto una prova per togliermi definitivamente il dubbio.


L'ho appena fatta anch'io, ed effettivamente il metodo ritorna 10. Quindi la variabile è passata per valore. Infatti guardate come viene compilata una chiamata ad un metodo con passaggio di valori. Il codice

int addTwo(int i, int j) {
return i + j;
}
è compilato così

Method int addTwo(int,int)
0 iload_1 // Push value of local variable 1 (i)
1 iload_2 // Push value of local variable 2 (j)
2 iadd // Add; leave int result on operand stack
3 ireturn // Return int result

Come si può vedere, nessun tipo reference è passato. Semplicemente, quando il metodo è chiamato, viene creato il suo frame nel quale sono posti, nelle posizioni 1 e 2 dell'area delle variabili locali, i valori passati.

vi e' quindi un constant string pool , un cosatant double pool ecc ecc ecc...
gli operatori + - ecc ecc ecc funzionano in modo da creare una nuova isntanza dell'oggetto.
quindi se faccio i+1 o i++ io vado a a creare un nuovo intero costante, e lo assegno al riferimento ma non vado a modificare il riferimento!!
Questo non è esatto. Infatti nella JVM non c'è una constant pool per ogni tipo, bensì una constant pool per ogni classe/interfaccia. Quando assegni un letterale ad una variabile non gli passi il riferimento alla constant pool, ma vai a modificare effettivamente il suo valore che è contenuto nel vettore delle variabili locali, il quale è contenuto nel frame del metodo che tu hai invocato.
L'incremento i++ che tu citi non avviene nel modo che hai detto. La JVM è una macchina stack-oriented; ogni operazione necessita che lo/gli operando/i siano in cima allo stack, e il risultato che ritorna è posto in cima allo stack. Per vedere meglio come funziona l'incremento, cito un esempio preso direttamente dalla Virtual Machine Specification. Questo metodo:
void spin() {
int i;
for (i = 0; i < 100; i++) {
; // Loop body is empty
}
}
viene compilato così

Method void spin()
0 iconst_0 // Push int constant 0
1 istore_1 // Store into local variable 1 (i=0)
2 goto 8 // First time through don't increment
5 iinc 1 1 // Increment local variable 1 by 1 (i++)
8 iload_1 // Push local variable 1 (i)
9 bipush 100 // Push int constant 100
11 if_icmplt 5 // Compare and loop if less than (i < 100)
14 return // Return void when done

Come si può vedere, le variabili locali sono immagazzinate con un indice (quello di i è 1 in questo caso). Quando vuoi incrementare i, l'istruzione iinc esegue l'operazione senza neanche usare l'operand stack, ma specifica direttamente l'indirizzo e l'incremento. Nessun nuovo oggetto viene creato.

bizzu
23-02-2004, 15:55
Quando ripassi di qua, non è che potresti cambiare titolo alla discussione? L'argomento mi sembra molto interessante e merita un titolo adatto, al posto di quello molto "generico" che hai messo ;) Thanks