Autore Topic: Differenza tra puntatori Java e C  (Letto 8404 volte)

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Differenza tra puntatori Java e C
« il: 29 Agosto 2012, 16:29:17 CEST »
*** TOPIC PROVENIENTE DA UNA DIVISIONE ***

Non lo so.. il fatto che ogni cosa sia un puntatore esclusi i tipi base secondo me è pericolosa se qualcuno non ha idea di cosa sta facendo. Spesso si leggono problemi di memory leak, spesso si sentono persone lamentarsi di nullpointerexception e così via. A volte sono bug e basta, altre volte vedi che qualcuno non ha idea di cosa stia manipolando.

Non per insistere, ma i puntatori sono una cosa ed il memory leak o i null pointer sono altra.

Agire sui puntatori significa avere il potere di manipolare gli indirizzi di memoria, ovvero decidere da codice a quale indirizzo fisico della ram far puntare una data variabile.

Tanto per intenderci una istruzione di questo tipo:
Codice (Java): [Seleziona]
String *x;
String y;

[...]

x = &y;

ovvero fai puntare ad x l'indirizzo di memoria su cui risiede la variabile y, non è possibile in java mentre è normale routine in C.

Quindi mentre in C hai la potenza di poter ottimizzare la memoria allocandola, distruggendola ed ottimizzando l'uso delle variabili giocando con i puntatori, con Java non puoi farlo e devi affidarti ad un pesante ed oneroso garbage collector.

Proprio sul memory leak java ha un passo in più rispetto a c. Tramite euristiche (onerose ma funzionali), infatti, java riesce a liberare molta più memoria rispetto ad un programmatore c distratto (che ha una gestione del tutto manuale della memoria).
« Ultima modifica: 30 Agosto 2012, 12:43:52 CEST da MarcoDuff »

Offline undead

  • Utente senior
  • ****
  • Post: 666
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #1 il: 29 Agosto 2012, 17:05:09 CEST »
Lo so cosa è un puntatore.  :-P

Ma questo?

Codice (Java): [Seleziona]
class MyShit{
                public int a;
        }
        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
               
                MyShit b = new MyShit();
                b.a = 1;
                test(b);
               
        }
       
        public void test(MyShit x){
                x.a++;
        }
x.a vale 2 cioè la variabile x è passata per reference, non per valore. Questo è esattamente come passare un puntatore in C e manipolarlo.
Prova a fare la stessa cosa con un tipo di dato base e vedrai che in quel caso viene passato per valore.

Concordo con quello che dici però per me questo codice in soldoni passa un puntatore, sottoforma di riferimento ad un oggetto. Cioè un indirizzo di memoria che è manipolabile all'interno di test.

 :-)

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #2 il: 29 Agosto 2012, 17:30:18 CEST »
Concordo con quello che dici però per me questo codice in soldoni passa un puntatore, sottoforma di riferimento ad un oggetto. Cioè un indirizzo di memoria che è manipolabile all'interno di test.

E' vero che ci sono analogie su quello che può essere fatto, ma il concetto essenziale è che non passi un "puntatore" ad una area di memoria manipolabile a basso livello. Anche perchè non è concepibile un linguaggio di programmazione in cui passi solo e soltanto per valore.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline undead

  • Utente senior
  • ****
  • Post: 666
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #3 il: 29 Agosto 2012, 17:38:21 CEST »
Fermi un attimo, stiamo dicendo tutti la stessa cosa ma è un problema di terminologia.

La spiegazione corretta, al netto delle parole che sono interpretabili, è che Java passa TUTTO per valore.

MA... MA... quando tu dichiari:

MyShit b;

b è un puntatore.

Quando passi b stai passando il VALORE del puntatore. Cioè l'indirizzo di memoria di quell'istanza di MyShit.

Questo fa si che se tu modifichi x.a alll'interno del metodo stai fisicamente modificando quella zona di memoria puntata da x.

Ma al tempo stesso se tu nulli x all'interno del metodo tu stai nullando un puntatore locale. Così come se gli assegni un'altra istanza con:

x = new MyShit;
x.a = 3;

quando esci dal metodo b.a vale sempre uno perchè tu non hai cambiato il puntatore fuori dal metodo, hai cambiato il puntatore locale all'interno del metodo.

Cito:

Citazione
To sum up: Java has pointers, and the value of the pointer is passed in. There's no way to actually pass an object itself as a parameter. You can only pass a pointer to an object.

Keep in mind, when you call:
 foo(d);
you're not passing an object; you're passing a pointer to the object.

http://javadude.com/articles/passbyvalue.htm

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #4 il: 29 Agosto 2012, 18:09:12 CEST »
Si avevo capito cosa intendevi quando dicevi che il "riferimento" di java è praticamente un "puntatore", però c'è una enorme differenza concettuale: il "puntatore" del C sopravvive anche se deallochi la rispettiva memoria, il "riferimento" del java invece muore con l'oggetto.

Infatti quando l'articolo dice...
Citazione
you're not passing an object; you're passing a pointer to the object.

...dice che passa un pointer to the object, cioè un riferimento ad un oggetto e non un puntatore di memoria. E' qualcosa di più complesso, perchè come ho detto sopra il puntatore alla memoria esiste indipendentemente dal contenuto della memoria, mentre il riferimento all'oggetto ha vita strettamente legata a quella dell'oggetto stesso.
« Ultima modifica: 29 Agosto 2012, 18:12:27 CEST da bradipao »
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline undead

  • Utente senior
  • ****
  • Post: 666
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #5 il: 29 Agosto 2012, 18:29:49 CEST »
Si ma dice anche:

Citazione
The value of the pointer being passed is similar to a memory address. Under the covers it may be a tad different, but you can think of it in exactly the same way. The value uniquely identifies some object on the heap.
 
However, it makes no difference how pointers are implemented under the covers. You program with them exactly the same way in Java as you would in C or C++.

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #6 il: 29 Agosto 2012, 19:03:53 CEST »
In tutta onestà a me sembra che l'articolista non abbia ben chiara la differenza tra i "puntatori" del C ed i "riferimenti agli oggetti" del java. Sono d'accordo che ci sono forti analogie nell'uso, ma concettualmente sono su due livelli diversi (poi è ovvio che il riferimento all'oggetto deve per forza usare i puntatori internamente). La differenza si spiega con poche parole: in java se un riferimento ad un oggetto non è null, allora l'oggetto esiste... per definizione. Cosa non vera nel caso dei pointer.

Sembra un aspetto minimale, ma è la fondamentale differenza tra java e c, un layer aggiuntivo di astrazione nell'uso della memoria, che ne automatizza molti aspetti, nel bene (molti meno leakage ed errori) e nel male (onere e complessità del GC).
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline undead

  • Utente senior
  • ****
  • Post: 666
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #7 il: 29 Agosto 2012, 19:12:48 CEST »
Per lui un reference è un alias di un oggetto e fa una differenza tra reference (&x) e puntatore (*x).

Comunque alla fine sono definizioni sfumate dipende molto dal contesto.
 :-)


Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #8 il: 30 Agosto 2012, 10:07:40 CEST »
In tutta onestà a me sembra che l'articolista non abbia ben chiara la differenza tra i "puntatori" del C ed i "riferimenti agli oggetti" del java.

Quoto in toto questa frase.

Fermi un attimo, stiamo dicendo tutti la stessa cosa ma è un problema di terminologia.

No, non stiamo affatto dicendo la stessa cosa.

Spero di spiegami meglio adesso, vado molto a basso livello, molte cose già le conosci, ma preferisco fare un riassunto (non molto rigoroso) di tutto per capire dove le nostre idee si dividono: che tu stia usando Java, C, PHP o Pascal hai sempre a che fare con un linguaggio di programmazione per computer che verrà in ogni caso tradotto in linguaggio macchina e che utilizza la RAM per immagazzinare i dati (che siano questi variabili, costanti, ecc...). Nella RAM i dati vengono salvati tramite degli indirizzi.

Questo significa che quando tu definisci una variabile intera X, automaticamente nella RAM viene riservata un'area di memoria di grandezza 4 byte (ma questo dipende dal linguaggio usato) per quella variabile ad un dato indirizzo della RAM (per indicare questo indirizzo uso l'operatore &, quindi l'indirizzo della variabile X è &X). Oltre allo spazio riservato alla variabile viene anche creato in automatico un puntatore a quell'indirizzo di memoria (per indicare questo puntatore uso l'operatore *, quindi il puntatore alla variabile X è *X).

Quindi ad ogni definizione di variabile viene creato uno spazio fisico dove viene salvata la variabile X nella RAM ad un certo indirizzo &X ed un puntatore *X che serve per manipolare quello spazio di memoria. Questo accade per tutti i linguaggi di programmazione comuni, nessuno escluso. Quindi tutti i linguaggi hanno i puntatori, tutti i linguaggi allocano lo spazio sulla ram, tutti i linguaggi identificano quello spazio tramite un indirizzo di memoria.

La differenza tra i vari linguaggi sta proprio nel fatto su cosa ti permettono di fare e su cosa tu puoi manipolare.

Hai detto bene che java passa i tipi primitivi come valore e gli oggetti come reference, ma il punto è proprio questo: in Java non hai la possibilità di scegliere visto che non hai accesso ai puntatori!

Mentre in C è in mano al programmatore la scelta di richiamare la tua funzione come

Codice (Java): [Seleziona]
test(b);
oppure come

Codice (Java): [Seleziona]
test(&b);
quindi sei tu a scegliere se utilizzare o meno il passaggio come reference o come valore (e di conseguenza utilizzare o gli operatori che ti danno accesso ai puntatori) e non è il linguaggio a scegliere per te!

Inoltre, limitarsi alla differenza tra passaggio per reference o valore per spiegare la potenza nel manipolare un puntatore è riduttivo! Ti faccio un altro esempio (ovviamente è una porcata, ma spero che faccia capire la differenza tra l'avere accesso ai puntatori e il non averlo): puoi modificare il valore di una variabile privata in Java da tutte le parti del codice che vuoi? La risposta è no, infatti in java non è possibile fare questo:

Codice (Java): [Seleziona]
public class TestClass {
        private int a;
       
        public int getIndirizzoMemoriaVariabileA() {
                return &a; // Caro Java, prova a restituire l'indirizzo se puoi, ah ah ah!!!
        }
}

In C, invece, avendo accesso all'indirizzo di memoria su cui risiede la variabile privata a posso farci quello che voglio dove voglio!!!

Offline undead

  • Utente senior
  • ****
  • Post: 666
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #9 il: 30 Agosto 2012, 11:19:42 CEST »
Il discorso dell'articolista per me è sensato poi se sui termini abbiamo idee diverse arriviamo a conclusioni che non sono del tutto identiche.

Lui dice che un reference è un alias di una variabile per cui se io passo un reference sto direttamente manipolando quella variabile, con tutto ciò che ne consegue. Un puntatore è comunque pass by value.

Mi spiego. Se in C passo il puntatore i_pMyPtr sto passando un indirizzo di memoria. Se all'interno del metodo riassegno localmente quel puntatore ad un altro indirizzo io sto manipolando il valore (in questo caso l'indirizzo di memoria) di quel puntatore locale. Perdo ogni collegamento con l'oggetto originale.

Ma in C io posso passare un reference al puntatore. In quel caso se io modifico localmente l'indirizzo puntato questo effetto si applica anche all'esterno del metodo poichè sto usando un reference.

L'articolista spiega che questa distinzione è netta: pass by value su un puntatore è una cosa, pass by reference è ben altro.

Il comportamento di java è il primo, non il secondo.

Che succede se io nullo un oggetto all'interno di un metodo? Se è un puntatore al di fuori del metodo non succede nulla. Se è un reference invece si.

Se prendiamo per buona questa differenza (reference->alias, valore->puntatore) l'articolo ha senso ma se le premesse che vengono fatte sono diverse il confronto perde di significato.

A mio avviso il puntatore è un puntatore in quanto tale, non si può identificare un puntatore solo dal fatto che il linguaggio ti permetta di fare o meno una certa operazione a basso livello.
Ogni variabile che contiene/punta ad un indirizzo di memoria e che viene passata per valore è di fatto un puntatore.

La discriminante è l'uso che ne fai, non le caratteristiche del linguaggio. Altrimenti arriviamo al paradosso che o i reference o i puntatori non esistono perchè se io scrivo questo:

Codice: [Seleziona]
.data

pippo dw 32000

.code

mov ax,13h
int 10h
mov ax,0a000h
mov es,ax
mov di,pippo
mov al,92
mov cx 32000
rep stosb

il mio puntatore è pippo ma non identificando univocamente un indirizzo di memoria cosa dovrei dedurne? Che in assembly i puntatori non esistono?

Per me quello è di fatto un puntatore, cioè una comunissima variabile che contiene un indirizzo di memoria e che se la passo sullo stack ad una funzione viene passata ovviamente per valore. E così come in java, se io manipolo localmente quella variabile che ho messo sullo stack, la variabile pippo rimane tale e quale.

La cosa si fa ancora più interessante se io carico l'indirizzo.

Codice: [Seleziona]
lea si,pippo ; prendo l'offset sul segmento dati (l'indirizzo effettivo) della variabile pippo
mov WORD PTR[si],0xFFFFh ; utilizzo l'indirizzo di pippo e ci scrivo 0xFFFFh

Questo cosa è? E' un puntatore o è un reference? Non ci facciamo fuorviare dalla direttiva WORD PTR che serve solo per stabilire la dimensione.

Quello è un reference, infatti io posso fare questo:

Codice: [Seleziona]
push ds
pop es ; copio il segmento dati nel segmento extra
lea di,pippo ; prendo l'offset della variabile pippo nel segmento dati
mov ax,0xFFFFh ; questo è dimensionato a 16 bit
stosw ; e qua scrivo... e pippo mi diventa 0xFFFFh

Questo secondo i canoni dell'articolista è un reference: ogni modifica a ds:si si applica anche a pippo. Se io passo si sullo stack o se chiamo una funzione e mi manipolo ds:si sto manipolando pippo.

Se parliamo di basso livello si vede che la differenza è netta ma il pattern è sempre il solito.

Con questo reference a pippo tra le mani io non posso accedere direttamente al puntatore, non posso fare altro che una cosa del tipo:

Codice: [Seleziona]
lodsw ; carico il CONTENUTO di pippo in AX
push 0xa000h
pop es ; faccio puntare es allo schermo VGA
mov di,ax ; prendo il valore di pippo
mox al,92
stosb ; scrivo 92 nel pixel puntato da pippo

Non c'è infatti un modo per tornare direttamente al valore del puntatore e non esiste alcun costrutto che da solo identifichi un reference (tipo &).

Di fatto mi trovo costretto a riconoscere la distinzione che fa l'articolista che è una differenza a livello di uso (l'uso che fai dell'indirizzo puntato da ds:si) e non di implementazione (perchè in assembly il costrutto è solo uno: ds:si punta a una zona di memoria e tu leggi/scrivi).

Quindi quando si parla di basso livello è un concetto estremamente relativo, &x non è una operazione a basso livello. mov es:[di],al lo è.

Se l'articolista dice di essere un compiler guy, cioè uno che poi deve tradurre &x in assembly, capisco che dal suo punto di vista a basso livello la distinzione ha assolutamente senso e per il comportamento che esprime java ogni oggetto è un puntatore perchè di fatto ne ha tutte le caratteristiche.

Quindi in breve: per me java ha i puntatori ma non ha i reference.
Poi secondariamente vale tutto quello che è stato detto e che non mi sono mai sognato di confutare: in C puoi ovviamente manipolare la memoria ad un livello più vicino all'hardware.

:-)

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #10 il: 30 Agosto 2012, 12:08:14 CEST »
Mi sa che non la finiremo mai (oltre al fatto che stiamo andando pesantemente off-topic, se la discussione continua la taglio in un nuovo topic!).

Quello che non riesco a spiegare è che non bisogna limitare la parola "puntatore" al passaggio di variabili come valore o reference, visto che i puntatori sono solo lo strumento che ti permette di farlo. Senza l'accesso al puntatore non puoi essere tu a decidere ma è il linguaggio che decide per te.

Grazie all'uso dei puntatori riesci a fare questo:

Devi gestire una variabile sia come carattere che come intero. Quindi definisco una variabile char e due puntatori a quella variabile in questo modo:
Codice (Java): [Seleziona]
char c;
char *pc;
int *pi;

pc = &c;
pi = &c;

Appena cambio il valore della variabile c, cambio in automatico il valore di *pc e di *pi. Se quindi mi serve il valore di tipo intero della variabile c faccio riferimento a *pi, mentre se mi serve il valore carattere faccio riferimento a *pc. Quindi puoi utilizzare la stessa area di memoria dando due significati ed interpretazioni diverse (int o char).

Nota bene che posso definire in modo indifferente la variabile c come "char" o "int" e addirittura posso anche non affidargli alcun tipo ed allocare soltanto lo spazio in memoria tramite un malloc.

Tutto questo in Java non puoi farlo, è un dato di fatto! E non puoi farlo perché non puoi manipolare i puntatori!
L'unica cosa che puoi fare è una operazione di casting tra i tipi, ovvero:

Codice (Java): [Seleziona]
(int)c
ma in questo modo (ed è questo il punto fondamentale) non interpreti l'area di memoria di c come un intero ma allochi un nuovo spazio di memoria dove salvi il contenuto del casting di c ad int.

Spero di essere stato più chiaro adesso!

Offline undead

  • Utente senior
  • ****
  • Post: 666
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #11 il: 30 Agosto 2012, 12:21:59 CEST »
Io la tua spiegazione la capisco e concordo al 100%.
D'altra parte non è una questione discutibile, nel senso che in C si possono fare cose che in Java non sono possibili.

Ma dal mio punto di vista nel tuo esempio la differenza tra java e c (e anche nell'esempio precedente) sta nel &.
E' quello che manca a java. Ma &c è un reference, non un puntatore.

Infatti in java puoi fare:

Codice (Java): [Seleziona]
Pippo a;
Pippo b;

b = a;

b.qualcosa();

stai manipolando a, quindi b è un puntatore. La possibilità di fare quello che dici in C è data dal reference non dal puntatore in se.

Comunque io avevo solo detto che non ho problemi con java ho espresso qualche perplessità riguardo al fatto che a volte avere questa gestione limitata e trasparente dei puntatori può creare dei problemi.

Alcuni si avvicinano al linguaggio e pensano che siccome è passato tutto per valore e non esistono reference allora quello che viene passato è l'oggetto e non il puntatore all'oggetto.

 ;-)

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Differenza tra puntatori Java e C
« Risposta #12 il: 30 Agosto 2012, 12:47:31 CEST »
Si, è chiaro che la discussione è basata sul significato che si da' alla parola puntatore.

Per me (e per Marco) il puntatore è un numero esadecimale a 32bit (sorvoliamo sulle possibili altre dimensioni) che identifica univocamente un byte nella memoria fisica dell'elaboratore (sorvoliamo anche sulla memoria virtuale che è arrivata dopo). Per noi quello è un "pointer" del C e non ha niente a che vedere con variabili, oggetti, funzioni, passaggio di parametri o altro. Passare un riferimento ad un oggetto, in generale non vuol dire passare il valore di un puntatore all'area di memoria dell'oggetto, posso benissimo passare una stringa che identifica un oggetto in un array associativo gigantesco che contiene tutti gli oggetti del sistema.

Se però si estende il concetto di puntatore, considerandolo astrattamente come un qualcosa che punta a qualcos'altro. Allora sono d'accordo che è un sinonimo di riferimento.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #13 il: 30 Agosto 2012, 13:49:53 CEST »
Alcuni si avvicinano al linguaggio e pensano che siccome è passato tutto per valore e non esistono reference allora quello che viene passato è l'oggetto e non il puntatore all'oggetto.

Ma questo non è vero!

I parametri di una funzione se sono primitivi sono passati come valore, se sono oggetti vengono passati come riferimento:
Codice (Java): [Seleziona]
package com.marcoduff.test;

public class TestClass {
        int a;
       
        public static void main(String[] args) {
                TestClass testClass = new TestClass();
                testClass.a = 1;
                int x = 1;
               
                System.out.println(testClass.a+" ---- "+x); // Stampa 1 ---- 1
                cambiaValori(testClass, x);
                System.out.println(testClass.a+" ---- "+x); // Stampa 2 ---- 1
                // Il valore di testClass.a è cambiato visto che testClass viene passato come riferimento
                // Il valore di x non cambia vista che x viene passato come valore
        }

        private static void cambiaValori(TestClass testClass, int x) {
                testClass.a++;
                x++;
        }
}

stai manipolando a, quindi b è un puntatore. La possibilità di fare quello che dici in C è data dal reference non dal puntatore in se.

Scusami, ma allora mi sa che il problema è che non ti è molto chiaro cosa sia un puntatore. Puntatore e variabile puntata sono due cose totalmente diverse, quindi la variabile b ed il puntatore alla variabile b sono due cose diverse che risiedono in posti diversi nella memoria.

Forse con questa frase mi farò capire meglio: "Anche un puntatore ha un suo indirizzo di memoria".

Codice (Java): [Seleziona]
TestClass a = new TestClass();

System.out.println(a); // Stampa com.marcoduff.test.TestClass@69e1e999


Questo è il massimo a cui posso arrivare in java.
Posso allocare una variabile a.
Posso conoscere (ma non utilizzare) l'indirizzo di memoria su cui risiede a (che è l'analogo di &a in C), ovvero 69e1e999.

Le mie informazioni sono finite.

In ogni caso a non è un puntatore ma un oggetto.

In C avrei anche questa possibilità di definire un puntatore a TestClass a in questo modo:
Codice (Java): [Seleziona]
TestClass *p;
p = &a;

Ma attenzione che p ha il valore "69e1e999" mentre &p ha un valore "b06c6be"!

Sia a che p sono due variabili.
a è una variabile di tipo TestClass.
p è una variabile di tipo Puntatore a TestClass (definizione impossibile in Java).
a risiede in una sua area di memoria.
p risiede in una sua area di memoria.
Il contenuto dell'area di memoria di p coincide con l'indirizzo di memoria in cui risiede a.

Ma in ogni caso la variabile TestClass a è una cosa ed il Puntatore a TestClass *p è un'altra. Come vedi ho due variabili diverse.
Nel tuo esempio java NON hai queste differenze ma chiami b una volta "oggetto" ed in un'altra "puntatore". Ma questo non è possibile: una variabile o è un oggetto o è un puntatore, non può essere tutte e due cose in contemporanea.

Offline undead

  • Utente senior
  • ****
  • Post: 666
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Re:Google ti odio, viva Apple/Microsoft/ecc...
« Risposta #14 il: 30 Agosto 2012, 15:22:41 CEST »
I parametri di una funzione se sono primitivi sono passati come valore, se sono oggetti vengono passati come riferimento:
E' qui l'inghippo. In Java i parametri di una funzione sono SEMPRE passati come valore.
Il pass-by-reference in Java non esiste. Nel caso di un puntatore il suo valore è, semplificando, l'indirizzo al quale esso punta.

Nell'articolo questo è spiegato bene.

"In short: Java has pointers and is strictly pass-by-value. There's no funky rules. It's simple, clean, and clear."

Citazione
Scusami, ma allora mi sa che il problema è che non ti è molto chiaro cosa sia un puntatore. Puntatore e variabile puntata sono due cose totalmente diverse, quindi la variabile b ed il puntatore alla variabile b sono due cose diverse che risiedono in posti diversi nella memoria.
Mi è chiaro cosa è un puntatore però tu stai dando come assodate delle cose che non lo sono affatto.

Quando tu dici che il puntatore ha il suo indirizzo questo significa poco. Ogni variabile ha un indirizzo!

Per esempio in un sistema a 32-bit con memoria indirizzata linearmente un puntatore (a prescindere dall'oggetto al quale sta puntando) rappresenta 4 byte di offset.
In un sistema a 16 bit, per esempio ai tempi del DOS, hai i puntatori near per il segmento corrente (16 bit) e i puntatori far (32-bit) per indirizzare al di fuori del segmento.
In una virtual machine hai altri tipi di indirizzi.

Ma sono sempre indirizzi. Per cui un puntatore ha un proprio indirizzo come ogni altra variabile e il valore del puntatore non è altro che un altro indirizzo di memoria.

Quindi a prescindere dal tipo di variabile ogni variabile ha un valore ed un indirizzo. Nel caso del puntatore c'è ovviamente un indirizzo che identifica la variabile puntatore e un indirizzo (o similare) che identifica un'altra zona di memoria che è il valore del puntatore.

Non ha senso dire che l'offset di un segmento è un indirizzo ma qualche identificativo di un oggetto all'interno di una virtual machine no. Nel loro contesto sono entrambi indirizzi.

Citazione
Ma attenzione che p ha il valore "69e1e999" mentre &p ha un valore "b06c6be"!
Hai fatto tre esempi in cui usi & ed è logico che in Java non si può... è quello che sto dicendo io: a Java mancano i reference.

Ma a livello di puntatori???

In C:
Pippo *p = new Pippo(1);

In Java:

Pippo p = new Pippo(1);

E' la stessa cosa. Anche in Java p è un indirizzo e non un oggetto. Se così non fosse non potresti fare p1 = p.

Continuiamo in C:

Pippo *p1 = p;
p1->qualcosa();

In Java:

Pippo p1 = p;
p1.qualcosa();

E' la stessa cosa.

Se passi p ad una funzione e la funzione lo manipola sia in Java che in C p viene cambiato. Se nulli/riassegni p all'interno della funzione sia in Java che in C quando esci p non viene nullato.
Se fai p1 = null o p = null sia in java che in C puoi usare l'altra variabile per accedere a quell'istanza di Pippo.

L'unica cosa che manca a java è l'aritmetica dei puntatori per cui io posso fare p++ o p[10] e quello mi salta al "prossimo" pippo o al decimo pippo, assumendo che siano contigui in memoria.

Quella è la differenza sostanziale a livello di puntatori e manca per il semplice fatto che non avendo i reference non servirebbe a niente!!!

Ma per il resto se si comporta come un puntatore, viene passato come un puntatore e sembra un puntatore... è probabile che sia un puntatore!  ;-)