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.nameche sarà dopo l' transformIntoHomeresecuzione 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.

Rafael Chinelato Del Nero

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 Stringoggetto 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 Stringdi 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 Stringoggetto è immutabile, il che significa che i campi all'interno di Stringsono definitivi e non possono essere modificati.

Rendere la Stringclasse immutabile ci offre un controllo migliore su uno degli oggetti più utilizzati di Java. Se il valore di a Stringpotesse essere modificato, creerebbero molti bug. Notare inoltre che non stiamo cambiando un attributo della Stringclasse; invece, gli stiamo semplicemente assegnando un nuovo Stringvalore. In questo caso, namenel changeToHomermetodo verrà passato il valore "Homer" . L ' String"Homer" sarà idoneo alla raccolta dei rifiuti non appena il changeToHomermetodo completa l'esecuzione. Anche se l'oggetto non può essere modificato, la variabile locale lo sarà.

Corde e altro ancora

Scopri di più sulla Stringclasse 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 StringBuilderclasse. L'esempio seguente è simile al precedente, ma presenta StringBuilderpiuttosto 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 Stringe 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 warriorProfessionvariabile, 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 and StringBuffer) 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.