Come si differenzia un riferimento Java da un puntatore C?

94

C ha dei puntatori e Java ha ciò che viene chiamato riferimenti. Hanno alcune cose in comune nel senso che tutti puntano a qualcosa. So che i puntatori in C memorizzano gli indirizzi a cui puntano. Fare riferimento anche a memorizzare l'indirizzo? In che modo sono diversi, a parte il fatto che il puntatore è più flessibile e soggetto a errori?

    
posta Gnijuohz 28.03.2012 - 09:46
fonte

4 risposte

139

I riferimenti potrebbero essere implementati memorizzando l'indirizzo. Solitamente i riferimenti Java saranno implementati come puntatori, ma ciò non è richiesto dalle specifiche. Possono utilizzare un ulteriore livello di riferimento indiretto per abilitare la raccolta dei dati inutili. Ma alla fine si ridurrà (quasi sempre) a puntatori (in stile C) coinvolti nell'implementazione di riferimenti (in stile Java).

Non puoi eseguire l'aritmetica del puntatore con i riferimenti. La differenza più importante tra un puntatore in C e un riferimento in Java è che non puoi effettivamente (e manipolare) il valore sottostante di un riferimento in Java. In altre parole: non puoi eseguire l'aritmetica del puntatore.

In C puoi aggiungere qualcosa a un puntatore (ad esempio l'indirizzo) o sottrarre qualcosa per indicare cose che sono "vicine" o puntare a luoghi che sono in qualsiasi posto.

In Java, un riferimento punta a una cosa e solo a quella cosa. Puoi fare in modo che una variabile abbia un riferimento diverso , ma non puoi semplicemente chiedere di indicare "la cosa dopo la cosa originale".

I riferimenti sono strongmente tipizzati. Un'altra differenza è che il tipo di riferimento è molto più strettamente controllato in Java rispetto al tipo di puntatore in C. In C puoi avere int* e convertirlo in char* e reinterpretare la memoria in quella posizione. Quella reinterpretazione non funziona in Java: puoi solo interpretare l'oggetto all'altra estremità del riferimento come qualcosa che è già (cioè puoi lanciare un riferimento Object a String riferimento solo se l'oggetto puntato è in realtà un String ).

Queste differenze rendono i puntatori C più potenti, ma anche più pericolosi. Entrambe le possibilità (aritmetica del puntatore e reinterpretazione dei valori puntati) aggiungono flessibilità a C e sono la fonte di alcuni del potere della lingua. Ma sono anche grandi fonti di problemi, perché se usate in modo errato possono facilmente interrompere le ipotesi su cui è costruito il codice. Ed è abbastanza facile usarli in modo errato.

    
risposta data 28.03.2012 - 10:02
fonte
7

I riferimenti C ++ sono di nuovo diversi.

Devono essere inizializzati e non possono essere nulli (almeno non in un programma ben formato) e non possono essere rimessi per riferirsi a qualcos'altro. un riferimento C ++ è molto più simile a un alias per un oggetto.

Un'altra importante differenza tra i puntatori e i riferimenti Java / C ++ è che è possibile prendere l'indirizzo di un puntatore non è possibile accedere all'indirizzo di un riferimento (infatti un riferimento C ++ non deve esistere effettivamente come oggetto in memoria) di conseguenza può avere un puntatore a un puntatore ma non un riferimento a un riferimento

    
risposta data 28.03.2012 - 10:31
fonte
4

Riferimenti Java e puntatori C differiscono esattamente in due punti:

  1. Non esiste l'aritmetica del puntatore per il primo.
  2. E non puoi creare un riferimento Java a quello che vuoi, puoi solo copiare quelli salvati da qualche parte accessibili (campi statici, campi di oggetti, variabili locali) o restituiti da invocazioni di funzioni (come le chiamate del costruttore), che quindi fare riferimento a oggetti Java (mai a tipi di base come riferimenti, char , int e così via).

Qualcuno ha scritto che i riferimenti sono strongmente tipizzati, perché non puoi forzare il compilatore a trattare un int* come char* .
Completamente a parte il fatto che quella particolare conversione è in realtà sicura , non c'è polimorfismo in C, quindi il confronto è un non-starter.
Certamente, Java è più strongmente tipizzato di C, non che questa sia una caratteristica dei riferimenti di C rispetto a Java, è necessario utilizzare il JNI per rompere la sicurezza di tipo (a parte ignorare le restrizioni generiche), ma anche in C devi < em> force il compilatore.

Qualcuno ha scritto che i riferimenti Java potrebbero essere implementati come puntatori C, a cui io dico sicuramente, poiché sono strettamente meno potenti, sulle macchine a 32 bit che sono in genere, se la JVM è implementata in C . Anche se su macchine a 64 bit, sono normalmente puntatori di oggetti ordinari compressi ("OOP compressi") per risparmiare spazio e larghezza di banda.
Ad ogni modo, i puntatori C non devono necessariamente essere equivalenti agli indirizzi hardware, anche se tipicamente (> 99% delle implementazioni) sono per motivi di prestazioni.
Infine, questo è un dettaglio di implementazione che non è esposto al programmatore.

    
risposta data 20.08.2015 - 23:29
fonte
-1

Sono leggermente diversi. In Java una copia del riferimento viene copiata nello stack di una funzione chiamata, puntando allo stesso oggetto della funzione chiamante e consentendo di manipolare quell'oggetto. Tuttavia non è possibile modificare l'oggetto a cui si riferisce la funzione di chiamata.

Considera il seguente codice java

public static void changeRValue(StringBuffer sb){
    sb = new StringBuffer("helllllo"); /*attempt to assign the reference
                                        to a new object*/
}
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer("hi");     //Create a new string buffer
    changeRValue(sb);                             //Call changeRValue
    System.out.println(sb.toString());            //Prints "hi" not "hello"
}

Ora considera un puntatore in c ++:

void func(Dog* dog){
    *dog = Dog("hello world"); //Change the value of dog to a new object
}

int main(int argc, const char * argv[]) {
    Dog dog1("hi");                            //Create a dog object
    func(&dog1);                               //pass the address of dog
    cout << dog1.name;                         //Prints "hello world" not hi.
    return 0;
}
    
risposta data 20.08.2015 - 16:13
fonte

Leggi altre domande sui tag