Domanda

Studio Java da alcuni mesi e ora sto iniziando a studiare C.

Sono un po 'confuso, avevo l'impressione che passare un oggetto per riferimento e passare un puntatore a quell'oggetto fossero la stessa cosa: pensavo che la differenza fosse che in Java tutto il passaggio degli oggetti veniva fatto automaticamente con i puntatori, dove come in C si devono effettivamente cospargere piccoli asterischi e e commerciali qua e là. Di recente, durante una conversazione, mi è stato assicurato che c'era una differenza!

Qual è la differenza tra passare per riferimento e passare un puntatore?

È stato utile?

Soluzione

Né Java C hanno riferimenti pass-by. Sono entrambi rigorosamente pass-by-value.

La semantica pass-by-reference indica che quando si modifica il valore del parametro nel metodo, il chiamante vedrà tale modifica nell'argomento.

Ora potresti pensare: " Ma questo è il caso di Java! Se cambio un oggetto durante il metodo, il chiamante vede quel cambiamento. & Quot; L'oggetto non è il parametro. Il parametro è solo la variabile - e se cambi il valore di quella variabile, il chiamante non lo vedrà. Ad esempio:

public void foo(Object x)
{
    x = null;
}

public void caller()
{
    Object y = new Object();
    foo(y);
    // y is still not null!
}

Se il parametro fosse realmente passato per riferimento, y sarebbe nullo in seguito. Invece, il valore di y è solo un riferimento e quel riferimento viene passato per valore. È confuso perché la parola "riferimento" è in entrambi i termini, ma sono cose diverse.

Potresti voler guardare il mio articolo sul passaggio di parametri C # per vedere cosa sarebbe possibile se Java avesse una semantica pass-by-reference, come fa C # quando (e solo quando) usi la parola chiave ref .

Puoi anche guardare i commenti a my Stack Overflow answer relativo all'argomento.

Altri suggerimenti

  

Pensavo che la differenza fosse che in Java tutto il passaggio di oggetti veniva fatto automaticamente con i puntatori, dove come in C uno deve effettivamente cospargere piccoli asterischi e e commerciali qua e là.

Conceptional, è abbastanza giusto. Se siamo pedanti (e questa è una buona cosa), possiamo anche dire che gli oggetti non vengono passati affatto in Java. Ciò che viene passato è sempre e solo il "puntatore", che in Java è chiamato riferimento. Tutte le indirette vengono eseguite automaticamente. Pertanto, quando fai " objref- > foo " invece di " objref.foo " in C e non puoi usare il punto perché lavori con un puntatore, in Java puoi comunque usare il punto perché non conosce nient'altro per accedere ai membri comunque. In C, puoi passare il puntatore (e qui è attualmente chiamato puntatore) e puoi passare l'oggetto stesso, nel qual caso viene passata una copia. In C, accedi all'oggetto a cui fa riferimento un puntatore indirettamente usando la stella o " - > " ;. In Java, l'unico modo per accedere agli oggetti è utilizzare il punto (objref.member).

Se siamo di nuovo pedanti (ora di nuovo più importanti), né in Java né in C c'è "passaggio per riferimento". Ciò che passiamo in Java è il riferimento / puntatore all'oggetto e in C o passiamo una copia dell'oggetto (caso ovvio) o passiamo di nuovo solo una copia di un puntatore all'oggetto. Quindi in entrambi i casi - Java e C - ciò che passiamo sono gli indirizzi degli oggetti. Non parlando di tipi java primitivi, che vengono copiati sia in Java che in C - anche se puoi anche passare il loro indirizzo in C, non c'è differenza tra un tipo aggregato (cioè una struttura) e un tipo "primitivo"; in C in che riguarda.

Le differenze sono sottili. A livello di assieme, in entrambi i casi l'indirizzo dell'oggetto viene passato alla funzione. Tuttavia, nel caso del puntatore il parametro è un puntatore indipendente che può essere utilizzato per modificare l'oggetto target (* pch = 'x') o per accedere a un oggetto diverso (pch = " newstr "). Nel caso di riferimento, il parametro viene automaticamente indirizzato all'oggetto target.

Credo che un puntatore sia una variabile che contiene un riferimento. Con & amp; è possibile ottenere una direzione della memoria (riferimento) e con * è possibile accedere al contenuto di una direzione della memoria. Suggerisco il libro Il linguaggio di programmazione C .

Saluti

True pass-by-reference significa che puoi assegnare un nuovo valore al riferimento e questo nuovo valore sarà visibile nel contesto chiamante proprio come all'interno del metodo chiamato.

In Java, questo non è possibile perché i riferimenti agli oggetti vengono passati per valore .

Alcune cose

  • C non ha riferimenti (nonostante C ++)
  • Java non ha puntatori
  • La differenza tra puntatori e riferimenti è che i puntatori sono praticamente indirizzi di memoria con cui è possibile calcolare. I riferimenti non possono essere calcolati con
  • Java e C passano per valore (quando si passa un oggetto in Java, il riferimento viene copiato nella funzione)

Se stai studiando C (anziché C ++), allora non ci sono riferimenti.

Il termine "passa per riferimento" in C significa semplicemente che stai passando un puntatore come indirizzo in cui verrà memorizzato il valore, in modo che la funzione possa modificarne il valore. Altrimenti, stai passando per valore, il che significa che una copia della variabile viene generata nello stack e le modifiche non hanno alcun impatto.

In molti modi questo è simile a quello che vedi in Java, tranne per il fatto che in Java non devi trasformare esplicitamente le cose in un puntatore o dereferirle. In altre parole, quando si passa un puntatore, l'indirizzo viene copiato nello stack, quindi se la funzione cambia il puntatore (anziché i dati a cui punta), le modifiche scompaiono al termine della funzione. Allo stesso modo, quando si passa un riferimento a un oggetto in Java, è possibile modificare il contenuto dell'oggetto (ad es. Chiamando funzioni), ma cambiando la varialbe in modo che punti ad un altro oggetto non avrà alcun effetto una volta usciti.

Se si utilizza C ++ (che assomiglia a C), è possibile passare per riferimento, nel qual caso non è necessario gestire i puntatori e le modifiche alla variabile nella funzione cambiano direttamente il valore esterno ( tranne per il fatto che non è possibile puntare a qualcos'altro).

C'è un recente articolo di Eric Lippert su questo. È un programmatore del compilatore C #, ma qualunque cosa lui dica ha abbastanza generalità per essere esteso ad altri linguaggi GC come Java:

http: // blogs .msdn.com / ericlippert / archive / 2009/02/17 / riferimenti-sono-non-addresses.aspx

Citazione dell'articolo:

  

I puntatori sono rigorosamente "più potenti" di riferimenti; qualsiasi cosa tu possa fare con i riferimenti che puoi fare con i puntatori. [...]

     

I puntatori sono in genere implementati come indirizzi. Un indirizzo è un numero che è un offset nella "matrice di byte" questo è l'intero spazio degli indirizzi virtuali del processo. [...]

     

Per tutti questi motivi non descriviamo i riferimenti come indirizzi nelle specifiche. La specifica dice solo che una variabile di tipo di riferimento "memorizza un riferimento" a un oggetto e lo lascia completamente vago su come potrebbe essere implementato. Allo stesso modo, una variabile puntatore memorizza "l'indirizzo" di un oggetto, che di nuovo viene lasciato piuttosto vago. Da nessuna parte diciamo che i riferimenti sono gli stessi degli indirizzi.

     

Quindi, in C # un riferimento è qualcosa di vago che ti consente di fare riferimento a un oggetto. Non puoi fare nulla con un riferimento se non dereference e confrontarlo con un altro riferimento per l'uguaglianza. E in C # un puntatore viene identificato come un indirizzo.

     

Contrariamente a un riferimento, puoi fare molto di più con un puntatore che contiene un indirizzo. Gli indirizzi possono essere manipolati matematicamente; puoi sottrarre l'uno dall'altro, puoi aggiungere numeri interi e così via. Le loro operazioni legali indicano che sono "numeri fantasiosi" quell'indice nella "matrice" quello è lo spazio degli indirizzi virtuali del processo.

Quei lettori che hanno familiarità con C / C ++ hanno probabilmente notato che compaiono riferimenti ad oggetti essere simile ai puntatori. Questo sospetto è sostanzialmente corretto. Un riferimento ad oggetto è simile a un puntatore di memoria. La differenza principale e la chiave della sicurezza di Java è quella non è possibile manipolare i riferimenti come è possibile puntatori reali. Pertanto, non è possibile causare un riferimento all'oggetto per indicare una posizione di memoria arbitraria o manipolarla come un numero intero.

  • java non supportato & amp; operatore quindi come puoi ottenere l'indirizzo dell'oggetto in Java.
  • In java il riferimento viene eseguito dall'oggetto, ad esempio

MyClass object1 = new MyClass ();

MyClass object2 = object1;

vale a dire. potresti pensare che object1 e object2 si riferiscano a oggetti separati e distinti. Tuttavia, questo sarebbe sbagliato. Invece, dopo l'esecuzione di questo frammento, object1 e object2 si riferiranno entrambi allo stesso oggetto. se cambi in uno qualsiasi degli altri effetti.

* non è possibile modificare l'indirizzo dell'oggetto dopo l'inizializzazione ovvero MyClass obj = new MyClass (); come riferimento in c ++, con oggetto è possibile modificare solo il valore dell'istanza dell'oggetto

Nota: java fornisce una funzione speciale         object1 è stato impostato su null, ma object2 punta ancora sull'oggetto originale.

Non sono sicuro di Java, ma in C # o VB.net puoi passare per valore o per riferimento

esempio che passa per riferimento

    static void Main(string[] args)
    {
        int x = 1;
        Foo(ref x);
        Console.WriteLine(x.ToString());//this will print 2
    }

    private static void Foo(ref int x)
    {
        x++;
    }

nota che x è uguale a 1 ma quando chiami il metodo Foo e passi x per riferimento quando x viene aumentato di uno in Foo, aumenta anche il valore originale

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top