In che modo un riferimento Java è diverso da un puntatore C?


97

C ha puntatori e Java ha quelli che vengono chiamati riferimenti. Hanno alcune cose in comune nel senso che indicano tutte qualcosa. So che i puntatori in C memorizzano gli indirizzi a cui puntano. Il riferimento memorizza anche l'indirizzo? In che modo differiscono se non che il puntatore è più flessibile e soggetto a errori?


10
nota C ++ ha anche riferimenti che sono diversi da puntatori o riferimenti java
— jk.

@jk. Ho pensato che sarebbe stato lo stesso di Java. Qual è la differenza?
— Gnijuohz,

17
I riferimenti C ++ non sono ricambiabili (ovvero non è possibile modificare l'oggetto designato) e non sono nullable (ovvero non è possibile validamente farli fare riferimento a nessun oggetto).
— AProgrammer

@Gnijuohz Sostituendo ciò che ha detto @AProgrammer: un finalriferimento in Java è quasi equivalente a un riferimento C ++. Il motivo per cui non sono esattamente equivalenti è che un riferimento C ++ non è inoltre nullable, mentre un finalriferimento in Java è nullable.
— Utku,

Risposte:


142

I riferimenti potrebbero essere implementati memorizzando l'indirizzo. Di solito i riferimenti Java verranno implementati come puntatori, ma ciò non è richiesto dalla specifica. Potrebbero utilizzare un ulteriore livello di riferimento indiretto per consentire una più semplice raccolta dei rifiuti. Ma alla fine si ridurrà (quasi sempre) a puntatori (stile C) coinvolti nell'implementazione di riferimenti (stile Java).

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

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

In Java, un riferimento indica solo una cosa. Puoi fare in modo che una variabile contenga un riferimento diverso , ma non puoi semplicemente chiederle di indicare "la cosa dopo la cosa originale".

I riferimenti sono fortemente tipizzati. Un'altra differenza è che il tipo di riferimento è molto più rigorosamente controllato in Java rispetto al tipo di puntatore in C. In C è possibile avere un int*cast e inserirlo in un char*e reinterpretare la memoria in quella posizione. Questa reinterpretazione non funziona in Java: puoi solo interpretare l'oggetto all'altro capo del riferimento come qualcosa che è già (cioè puoi lanciare un Objectriferimento a Stringriferimento solo se l'oggetto indicato è effettivamente a String).

Queste differenze rendono i puntatori C più potenti, ma anche più pericolosi. Entrambe queste possibilità (puntatore aritmetico e reinterpretazione dei valori indicati) aggiungono flessibilità a C e sono la fonte di parte del potere del linguaggio. Ma sono anche grandi fonti di problemi, perché se usati in modo errato possono facilmente infrangere i presupposti che il tuo codice è costruito intorno. Ed è abbastanza facile usarli in modo errato.


18
+1 per potenza . Non fare affidamento sui dettagli di implementazione.
— un CVn il

2
+1 La raccolta dei rifiuti non merita di essere menzionata come punto in grassetto specifico? È un altro modo in cui i puntatori C sono più potenti ma anche più pericolosi (rischio di puntini penzolanti alla memoria liberata che causa corruzione della memoria, rischio di perdite di memoria)
— MarkJ

Un'altra differenza tra riferimenti e puntatori è che un puntatore in C può essere convertito in una sequenza di numeri (ad es. Usando memcpyper spostarne uno in a char[]) e viceversa. Se un puntatore viene convertito in una sequenza di numeri che viene memorizzata da qualche parte (forse mostrato sullo schermo e copiato dall'operatore su una distinta di carta), tutte le copie del puntatore all'interno del computer vengono distrutte e quella sequenza di numeri viene convertita tornando a un puntatore (forse dopo essere stato digitato dall'operatore), il puntatore deve ancora puntare alla stessa cosa che aveva fatto prima. Un programma che ...
— supercat

... visualizzare un puntatore come numeri, quindi convertire i numeri immessi manualmente in un puntatore, potrebbe essere "malvagio", ma non invocherebbe alcun comportamento indefinito a meno che l'operatore non abbia digitato numeri che non erano stati mostrati per formare un valido puntatore. La garbage collection per scopi generici è quindi impossibile in C completamente portatile, perché non c'è modo che il computer possa sapere se una copia di un puntatore potrebbe esistere da qualche parte nell'universo.
— supercat

Secondo JLS, §4.3.1, i riferimenti in Java sono puntatori, quindi "Normalmente i riferimenti Java verranno implementati come puntatori, ma ciò non è richiesto dalle specifiche". è falso.
— Lew Bloch,

8

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 ripristinati per fare riferimento a qualcos'altro. un riferimento C ++ è molto più simile a un alias per un oggetto.

Un'altra importante differenza tra puntatori e riferimenti Java / C ++ è che puoi prendere l'indirizzo di un puntatore a cui non puoi accedere all'indirizzo di un riferimento (in effetti un riferimento C ++ non deve in realtà esistere come oggetto in memoria) di conseguenza puoi avere un puntatore a un puntatore ma non un riferimento a un riferimento


4

Riferimenti Java e puntatori C differiscono esattamente in due punti:

  1. Non c'è aritmetica puntatore per il primo.
  2. E non è possibile creare un riferimento Java a ciò che si desidera, è possibile copiare solo 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 fanno tutti riferimento a Java oggetti (mai a tipi di base come riferimenti, char, inte così via).

Qualcuno ha scritto che i riferimenti sono fortemente tipizzati, perché non è possibile forzare il compilatore a trattare un int*come char*.
A parte il fatto che quella particolare conversione è effettivamente sicura , non c'è polimorfismo in C, quindi il confronto non è un inizio.
Certamente Java è più fortemente tipizzato di C, non che sia una caratteristica dei puntatori C rispetto ai riferimenti Java, è necessario utilizzare JNI per interrompere la sicurezza dei tipi (oltre a ignorare le restrizioni generiche), ma anche in C è necessario forzare il compilatore.

Qualcuno ha scritto che i riferimenti Java possono essere implementati come puntatori C, alla quale dico sicuro, in quanto sono strettamente meno potente, su macchine 32Bit che in genere sono, se la JVM è implementato in C . Sebbene su macchine a 64 bit, sono normalmente puntatori di oggetti ordinari compressi ("OOP compressi") per risparmiare spazio e larghezza di banda.
In ogni caso, questi puntatori C non devono necessariamente essere equivalenti agli indirizzi hardware, anche se in genere (> 99% delle implementazioni) sono per motivi di prestazioni.
Infine, si tratta di un dettaglio di implementazione che non è esposto al programmatore.


-1

Sono leggermente diversi. In Java una copia del riferimento viene copiata nello stack di una funzione chiamata, indicando lo stesso oggetto della funzione chiamante e consentendo di manipolarlo. Tuttavia, non è possibile modificare l'oggetto a cui fa riferimento la funzione chiamante.

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;
}

Ho pensato di aggiungere che potrebbe essere visto come simile a un cane da
— costante

2
È possibile modificare l'oggetto puntato in Java con la stessa facilità di C ++. Devi solo avere accesso ai membri giusti. Gli oggetti Java non hanno operatori di assegnazione perché Java non supporta il sovraccarico dell'operatore definito dall'utente, quindi non è possibile utilizzare un operatore sovraccarico, un grosso problema. Questa mancanza di Java non ha nulla a che fare con il fatto che i riferimenti Java sono gli stessi dei puntatori C ++ privi di aritmetica dei puntatori.
— Deduplicatore
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.