2010-10-06 11 views
5


Sono confuso nella seguente:
In C++ possiamo passare un parametro a una funzione per riferimento (avendo dichiarata come una variabile puntatore o riferimento) e se modificarlo all'interno funzione, le modifiche si riflettono sul chiamante quando la funzione ritorna.
Questo non sta accadendo in Java e non sono sicuro di aver capito perché.Java vs C++ passare riferimento

E.g. questo è un metodo da un oggetto X

public boolean aMethod(int id, myClass aClass) 
{ 
    //do some logic 
    aClass = new MyClass(); 
    //configure argument object aClass 
    return true; 
} 

Nel codice chiamante:

//some code processing 
myClass obj = null; 
if(X.aMethod(2,obj)) 
{ 
    obj.methodA();//start using the object 
} 

lo uso in C++, cioè per restituire un risultato che notifica che il parametro funzione può essere utilizzata, ma in Java questo non funziona.
Inserisco il ramo if (X.aMethod (2, obj) ma l'oggetto è nullo. Perché è nulla?
Non ho assegnato un indirizzo di memoria dall'heap usando new all'interno del metodo aMethod (int id, myClass aClass)? Non sto passando "l'indirizzo" di obj nella funzione? Mi aspettavo di avere l'oggetto correttamente costruito e utilizzabile nel codice chiamante. Ho frainteso qualcosa riguardo alla memoria in Java?

+1

possibile duplicato di [qual è la differenza tra il passaggio per riferimento e chiamata per riferimento?] (Http://stackoverflow.com/questions/3660180/what-is-the-difference-between-pass-by-reference-and-call-by-reference) –

risposta

26

Java passa tutto in base al valore - compresi i riferimenti.

Ciò significa che se si passa un oggetto, è possibile modificare le proprietà di tale oggetto, e saranno persistono dopo il ritorno, ma non è possibile sostituire l'oggetto nella sua interezza con una completamente nuova oggetto, poiché non è possibile modificare effettivamente il riferimento - solo ciò a cui fa riferimento il riferimento.

Prima linea aClass =:

Outside the function: 

    obj ---> <foo> 

Inside the function: 

    aClass ---> <foo> 

Dopo la vostra linea aClass =:

Inside the function: 

    aClass ---> <bar> 

Outside the function: 

    obj ---> <foo> 

La cosa fondamentale da notare qui è che aClass non punta a obj - punta a <foo>. Non stai passando l'indirizzo di obj, stai passando l'indirizzo di ciò che obj punti a. Pertanto, quando si modifica a che punti aClass, non si tocca obj.


In un modo alternativo di pensare a questo proposito:

In Java,

Bar foo = new Bar(); 

è equivalente a C++,

Bar *foo = new Bar(); 

Così, quando si passa foo a una funzione , non stai passando l'indirizzo di foo - stai passando l'indirizzo di e oggetto assegnato. Java non ha lo stile & -operator che fa riferimento a C/C++.

+0

'nuova barra()', vuoi dire. :) –

+0

@Jonathan oops, errore di battitura.:) – Amber

1

Java non può "passare per riferimento".

Java utilizza "passaggio di valore".

+0

La tua risposta non fornisce nulla di nuovo (sostanzialmente ripetendo ciò che altre persone hanno già detto in dettaglio) e confonde/ingannare le persone. Sebbene Jave usi "passa per valore" ma le persone possono ancora modificare le proprietà dell'oggetto passato. Tuttavia non possono riassegnare un oggetto completamente nuovo (ciò che l'OP vuole fare). –

0

Considerate la vostra argomenti oggetto (in Java) passati come tale (illustrato in C++):

void method(TObject* arg); 
+0

Dovrebbe essere il metodo 'void (TObject * & arg);'? – Ishtar

+0

@Ishtar no, 'metodo void (TObject * & arg)' è un riferimento a un puntatore.arg può essere modificato (per puntare a un altro indirizzo) internamente, e si riflettono esternamente, in modo tale che l'argomento del client possa puntare a un altro indirizzo quando restituisce 'method (arg)' Java passa gli oggetti come puntatori/per indirizzo. Gli sviluppatori Java preferiscono chiamarlo 'in base al valore', ma da un punto di vista C++ viene passato dal puntatore (o dall'indirizzo), con la lingua che estrae quel fatto (e puntatori del tutto). cont ... – justin

+0

@Ishtar parte 2: in C++, passa per valore == passa una copia dell'oggetto, non c'è copia con Java qui, quindi passare un oggetto Java in sintassi C++ è analogo a: 'metodo void (TObject * arg);' – justin

3

in C++ che cosa accadrebbe se avete fatto queste cose:

void myFunct(int * pInt) { 
    pInt = // something; 
} 

// caller 
int x; 
int * myPointer = & x; 
myFunc(myPointer); 
// where does myPointer point now? 

l'assegnazione all'interno myFunc ha nessun effetto sul puntatore del chiamante. Ora, se MyFunct ha preso invece puntatore al puntatore

void myFunct(int ** ppInt) { 
    *ppInt = // something; 
} 

o un riferimento al puntatore allora si sarebbe vedere un cambiamento nel chiamante, e questo è quello che suppongo che avete fatto.

In Java

void myFunct (Integere anInteger) { 
     // anInteger is reference to whatever is passed 
     anInteger = new Integer(99); // no effect on caller 
} 

abbiamo davvero passiamo riferimenti alla funzione, anInteger sopra è un riferimento a un oggetto di proprietà del chiamante, ma anInteger è un valore locale al metodo assegnando ad essa è la stessa come assegnazione a una puntata nel primo esempio, nessun effetto sul chiamante.

2

Il commento nel vostro esempio suggerisce che esiste il metodo aMethod per configurare l'oggetto. . Così, invece di passare a nulla, come su un'istanza dell'oggetto prima e poi passare in alternativa, è possibile effettuare il metodo restituisce l'oggetto intead, in questo modo:

public boolean aMethod(int id) 
{ 
    myClass aClass = new MyClass(); 
    return myclass; 
} 

E:

myClass obj = X.aMethod(2); 
if(obj != null) 
{ 
    obj.methodA();//start using the object 
} 

In alternativa, preferisco renderlo una convenzione che aMethod dovrebbe sempre restituire un oggetto valido. Se non è possibile, ad esempio a causa di un errore nella configurazione, fare in modo che il metodo generi un'eccezione.