In breve, stai confondendo la riassegnazione di una variabile locale con la modifica di un oggetto condiviso. sb.append()
non modifica la variabile sb
, modifica l'oggetto a cui fa riferimento la variabile. Ma number = 3
modifica la variabile number
assegnandole un nuovo valore. Gli oggetti sono condivisi tra le chiamate ai metodi, ma le variabili locali no. Quindi assegnando una variabile locale a un nuovo valore non avrà alcun effetto al di fuori del metodo, ma la modifica di un oggetto lo farà. Un po 'semplificato: se usi un punto ( .
), stai modificando un oggetto, non una variabile locale.
La confusione è probabilmente dovuta a una terminologia confusa. "Riferimento" indica due cose diverse in contesti diversi.
1) Quando si parla di oggetti e variabili Java, un riferimento è un "handle" per un oggetto. In senso stretto, una variabile non può contenere un oggetto, contiene un riferimento a un oggetto. I riferimenti possono essere copiati, quindi due variabili possono ottenere un riferimento allo stesso oggetto. Per es.
StringBuilder a = new StringBuilder();
StringBuilder b = a; // a and b now references the same object
a.writeLine("Hello"); // modify the shared object
b.toString() // -> "Hello"
Quando un oggetto viene passato a un metodo come parametro, è anche il riferimento che viene copiato, quindi il metodo chiamato può modificare lo stesso oggetto. Questo è anche chiamato "Chiama per condivisione".
void main(){
String builder b = new StringBuilder();
otherMethod(b);
b.toString(); // --> "Hello" because the shared object is modified
}
void otherMethod(StringBuilder b){
b.write("Hello"); // modify the shared object
}
Ma otherMethod può solo modificare l'oggetto condiviso, non può modificare nessuna variabile locale nel metodo chiamante. Se la funzione chiamata assegna un nuovo valore ai propri parametri, non influisce sulla funzione di chiamata.
void main(){
String builder b = new StringBuilder();
b.writeLine("Hello");
otherMethod(b);
b.toString(); // --> "Hello" because the shared object is NOT modified
}
void otherMethod(StringBuilder b){
b = new StringBuilder(); // assign a new object to b
b.write("Goodbye"); // modify the new object
}
Quindi devi essere chiaro sulla distinzione tra la modifica di un oggetto condiviso (attraverso la modifica di campi o il metodo di chiamata sull'oggetto) e l'assegnazione di un nuovo valore a una variabile o parametro locale.
2) Quando si parla di strategia di valutazione (come i parametri sono passati in funzione) nella teoria generale del linguaggio informatico, call-by-reference e call-by-value significa qualcosa di molto diverso.
Call-by-value, che supporta Java, significa che i valori degli argomenti vengono copiati nei parametri quando si chiamano i metodi. Il valore può essere un riferimento, motivo per cui la funzione chiamata otterrà un riferimento all'oggetto condiviso. In modo confuso, Java si dice "passi i riferimenti per valore", che è abbastanza diverso dalla chiamata per riferimento.
Se una lingua supporta call-by-reference, una funzione può cambiare il valore di una variabile locale nella funzione di chiamata . Java non supporta questo, che è mostrato nell'esempio sopra. Chiamata per riferimento significa che la funzione chiamata ottiene un riferimento alla variabile locale utilizzata come argomento nella chiamata. Questa nozione è completamente estranea a Java, dove semplicemente non abbiamo il concetto di riferimento a una variabile locale. Abbiamo solo riferimenti agli oggetti, mai alle variabili locali.
Per mostrare come funziona la chiamata per riferimento, possiamo guardare C # che fa supporto per riferimento con il modificatore ref
:
void main(){
String builder b = new StringBuilder();
b.writeLine("Hello");
otherMethod(ref b);
b.toString(); // --> "Goodbye" because otherMethod changed b to point to the new object
}
void otherMethod(ref StringBuilder b){
b = new StringBuilder(); // assign a new object to b
b.write("Goodbye"); // modify the new object
}
Qui otherMethod () modifica effettivamente la variabile locale b in main ().
Quindi per quanto riguarda le primitive come interi, booleani ecc.? Questi sono immutable che significa che non possono essere modificati come possono fare gli oggetti. Dal momento che non possono essere modificati, la domanda se sono condivisi o meno è discutibile, poiché non vi è alcuna differenza osservabile se sono condivisi o copiati.
Nota: non ho inventato la terminologia, quindi non incolpare il messenger. Preferisco di gran lunga i termini chiamata per condivisione o chiamata per oggetto che è più intuitivo per Java, ma resta il fatto che i termini call-by-value e call-by-reference è una terminologia stabilita e la specifica Java stessa utilizza il termine call-by-value.