Java passa per riferimento o passa per valore?
Molti linguaggi di programmazione consentono il passaggio di parametri per riferimento o per valore . In Java, possiamo passare i parametri solo per valore . Ciò impone alcuni limiti e solleva anche interrogativi. Ad esempio, se il valore del parametro viene modificato nel metodo, cosa succede al valore dopo l'esecuzione del metodo? Potresti anche chiederti come Java gestisce i valori degli oggetti nell'heap di memoria. Questo Java Challenger ti aiuta a risolvere queste e altre domande comuni sui riferimenti agli oggetti in Java.
Ottieni il codice sorgente
Ottieni il codice per questo Java Challenger. Puoi eseguire i tuoi test mentre segui gli esempi.
I riferimenti agli oggetti vengono passati per valore
Tutti i riferimenti agli oggetti in Java vengono passati per valore. Ciò significa che una copia del valore verrà passata a un metodo. Ma il trucco è che passare una copia del valore cambia anche il valore reale dell'oggetto. Per capire perché, inizia con questo esempio:
public class ObjectReferenceExample { public static void main(String... doYourBest) { Simpson simpson = new Simpson(); transformIntoHomer(simpson); System.out.println(simpson.name); } static void transformIntoHomer(Simpson simpson) { simpson.name = "Homer"; } } class Simpson { String name; }
Quale pensi simpson.name
che sarà dopo l' transformIntoHomer
esecuzione del metodo?
In questo caso, sarà Homer! Il motivo è che le variabili oggetto Java sono semplicemente riferimenti che puntano a oggetti reali nell'heap di memoria. Pertanto, anche se Java passa i parametri ai metodi in base al valore, se la variabile punta a un riferimento a un oggetto, verrà modificato anche l'oggetto reale.
Se non sei ancora del tutto chiaro come funziona, dai un'occhiata alla figura sotto.

I tipi primitivi vengono passati per valore?
Come i tipi di oggetto, anche i tipi primitivi vengono passati per valore. Puoi dedurre cosa accadrà ai tipi primitivi nel seguente esempio di codice?
public class PrimitiveByValueExample { public static void main(String... primitiveByValue) { int homerAge = 30; changeHomerAge(homerAge); System.out.println(homerAge); } static void changeHomerAge(int homerAge) { homerAge = 35; } }
Se hai stabilito che il valore cambierà in 30, hai ragione. È 30 perché (di nuovo) Java passa i parametri dell'oggetto per valore. Il numero 30 è solo una copia del valore, non il valore reale. I tipi primitivi vengono allocati nella memoria dello stack, quindi verrà modificato solo il valore locale. In questo caso, non esiste alcun riferimento all'oggetto.
Passaggio di riferimenti a oggetti immutabili
E se facessimo lo stesso test con un String
oggetto immutabile ?
Il JDK contiene molte classi immutabili. Gli esempi includono i tipi di involucro Integer
, Double
, Float
, Long
, Boolean
, BigDecimal
, e, naturalmente, il ben noto String
di classe.
Nel prossimo esempio, nota cosa succede quando cambiamo il valore di a String
.
public class StringValueChange { public static void main(String... doYourBest) { String name = ""; changeToHomer(name); System.out.println(name); } static void changeToHomer(String name) { name = "Homer"; } }
Quale pensi che sarà l'output? Se hai indovinato "", congratulazioni! Ciò accade perché un String
oggetto è immutabile, il che significa che i campi all'interno di String
sono definitivi e non possono essere modificati.
Rendere la String
classe immutabile ci offre un controllo migliore su uno degli oggetti più utilizzati di Java. Se il valore di a String
potesse essere modificato, creerebbero molti bug. Notare inoltre che non stiamo cambiando un attributo della String
classe; invece, gli stiamo semplicemente assegnando un nuovo String
valore. In questo caso, name
nel changeToHomer
metodo verrà passato il valore "Homer" . L ' String
"Homer" sarà idoneo alla raccolta dei rifiuti non appena il changeToHomer
metodo completa l'esecuzione. Anche se l'oggetto non può essere modificato, la variabile locale lo sarà.
Corde e altro ancora
Scopri di più sulla String
classe di Java e altro: guarda tutti i post di Rafael nella serie Java Challengers.
Passaggio di riferimenti a oggetti modificabili
Diversamente String
, la maggior parte degli oggetti nel JDK sono mutabili, come la StringBuilder
classe. L'esempio seguente è simile al precedente, ma presenta StringBuilder
piuttosto che String
:
static class MutableObjectReference { public static void main(String... mutableObjectExample) { StringBuilder name = new StringBuilder("Homer "); addSureName(name); System.out.println(name); } static void addSureName(StringBuilder name) { name.append("Simpson"); } }
Puoi dedurre l'output di questo esempio? In questo caso, poiché stiamo lavorando con un oggetto modificabile, l'output sarà "Homer Simpson". Potresti aspettarti lo stesso comportamento da qualsiasi altro oggetto modificabile in Java.
Hai già imparato che le variabili Java vengono passate per valore, il che significa che viene passata una copia del valore. Ricorda solo che il valore copiato punta a un oggetto reale nell'heap di memoria Java. Passare per valore cambia ancora il valore dell'oggetto reale.
Accetta la sfida dei riferimenti agli oggetti!
In questo Java Challenger testeremo ciò che hai imparato sui riferimenti agli oggetti. Nell'esempio di codice riportato di seguito, vedi la classe immutabile String
e mutabile StringBuilder
. Ciascuno viene passato come parametro a un metodo. Sapendo che Java passa solo per valore, quale sarà l'output una volta eseguito il metodo principale di questa classe?
public class DragonWarriorReferenceChallenger { public static void main(String... doYourBest) { StringBuilder warriorProfession = new StringBuilder("Dragon "); String warriorWeapon = "Sword "; changeWarriorClass(warriorProfession, warriorWeapon); System.out.println("Warrior=" + warriorProfession + " Weapon=" + warriorWeapon); } static void changeWarriorClass(StringBuilder warriorProfession, String weapon) { warriorProfession.append("Knight"); weapon = "Dragon " + weapon; weapon = null; warriorProfession = null; } }
Ecco le opzioni, controlla alla fine di questo articolo la chiave di risposta.
A : Warrior = null Weapon = null
B : Guerriero = Drago Arma = Drago
C : Warrior = Dragon Knight Arma = Dragon Sword
D : Guerriero = Dragon Knight Arma = Spada
Cos'è appena successo?
Il primo parametro nell'esempio precedente è la warriorProfession
variabile, che è un oggetto mutabile. Il secondo parametro, l'arma, è immutabile String
:
static void changeWarriorClass(StringBuilder warriorProfession, String weapon) { ... }
Now let’s analyze what is happening inside this method. At the first line of this method, we append the Knight
value to the warriorProfession
variable. Remember that warriorProfession
is a mutable object; therefore the real object will be changed, and the value from it will be “Dragon Knight.”
warriorProfession.append("Knight");
In the second instruction, the immutable local String
variable will be changed to “Dragon Sword.” The real object will never be changed, however, since String
is immutable and its attributes are final:
weapon = "Dragon " + weapon;
Finally, we pass null
to the variables here, but not to the objects. The objects will remain the same as long as they are still accessible externally--in this case through the main method. And, although the local variables will be null, nothing will happen to the objects:
weapon = null; warriorProfession = null;
From all of this we can conclude that the final values from our mutable StringBuilder
and immutable String
will be:
System.out.println("Warrior=" + warriorProfession + " Weapon=" + warriorWeapon);
The only value that changed in the changeWarriorClass
method was warriorProfession
, because it’s a mutable StringBuilder
object. Note that warriorWeapon
did not change because it’s an immutable String
object.
The correct output from our Challenger code would be:
D: Warrior=Dragon Knight Weapon=Sword.
Video challenge! Debugging object references in Java
Debugging is one of the easiest ways to fully absorb programming concepts while also improving your code. In this video you can follow along while I debug and explain object references in Java.
Common mistakes with object references
- Trying to change an immutable value by reference.
- Trying to change a primitive variable by reference.
- Expecting the real object won't change when you change a mutable object parameter in a method.
What to remember about object references
- Java always passes parameter variables by value.
- Object variables in Java always point to the real object in the memory heap.
- A mutable object’s value can be changed when it is passed to a method.
- An immutable object’s value cannot be changed, even if it is passed a new value.
- “Passing by value” refers to passing a copy of the value.
- “Passing by reference” refers to passing the real reference of the variable in memory.
Learn more about Java
- Get more quick code tips: Read all of Rafael's posts in the JavaWorld Java Challengers series.
- Learn more about mutable and immutable Java objects (such as
String
andStringBuffer
) and how to use them in your code. - Potresti essere sorpreso di apprendere che i tipi primitivi di Java sono controversi. In questa funzione, John I. Moore sostiene la necessità di mantenerli e di imparare a usarli bene.
- Continua a sviluppare le tue capacità di programmazione Java nella Java Dev Gym.
- Se ti è piaciuto il debug dell'ereditarietà Java, guarda altri video nella playlist di video Java Challenges di Rafael (i video di questa serie non sono affiliati a JavaWorld).
- Vuoi lavorare su progetti senza stress e scrivere codice privo di bug? Vai al NoBugsProject per la tua copia di No Bugs, No Stress - Crea software che cambia la vita senza distruggerti .
Questa storia, "Java passa per riferimento o passa per valore?" è stato originariamente pubblicato da JavaWorld.