Prolazi li Java referencom ili vrijednošću?

Mnogi programski jezici omogućuju prosljeđivanje parametara po referenci ili vrijednosti . U Javi parametre možemo prosljeđivati ​​samo prema vrijednosti . To nameće neka ograničenja i također postavlja pitanja. Na primjer, ako se vrijednost vrijednosti parametra promijeni u metodi, što se događa s vrijednošću nakon izvršenja metode? Također se možete zapitati kako Java upravlja vrijednostima objekata u hrpi memorije. Ovaj Java Challenger pomaže vam riješiti ova i druga uobičajena pitanja o referencama objekata u Javi.

Nabavite izvorni kod

Nabavite kod za ovaj Java Challenger. Možete provoditi vlastite testove dok slijedite primjere.

Referencije objekata prenose se prema vrijednosti

Sve reference na objekte u Javi prenose se prema vrijednosti. To znači da će se kopija vrijednosti proslijediti metodi. No, trik je u tome što dodavanje kopije vrijednosti mijenja i stvarnu vrijednost predmeta. Da biste razumjeli zašto, počnite s ovim primjerom:

 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; } 

Što mislite koja simpson.nameće biti nakon izvršenja transformIntoHomermetode?

U ovom će slučaju to biti Homer! Razlog je taj što su Java objektne varijable jednostavno reference koje upućuju na stvarne objekte u hrpi memorije. Stoga, iako Java prosljeđuje parametre metodama po vrijednosti, ako varijabla upućuje na referencu objekta, stvarni objekt također će se promijeniti.

Ako vam još uvijek nije sasvim jasno kako to funkcionira, pogledajte donju sliku.

Rafael Chinelato Del Nero

Prolaze li primitivni tipovi po vrijednosti?

Poput tipova objekata, primitivni tipovi također se prenose prema vrijednosti. Možete li zaključiti što će se dogoditi s primitivnim vrstama u sljedećem primjeru koda?

 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; } } 

Ako ste utvrdili da će se vrijednost promijeniti na 30, u pravu ste. To je 30 jer (opet) Java parametre objekta prosljeđuje prema vrijednosti. Broj 30 je samo kopija vrijednosti, a ne stvarna vrijednost. Primitivni tipovi dodijeljeni su u memoriji stoga, pa će se promijeniti samo lokalna vrijednost. U ovom slučaju ne postoji referenca na objekt.

Prolazak referenci nepromjenjivih objekata

Što ako bismo isti test radili s nepromjenjivim Stringobjektom?

JDK sadrži mnoge nepromjenjive klase. Primjeri uključuju vrste omot Integer, Double, Float, Long, Boolean, BigDecimal, i, naravno, vrlo dobro poznata Stringklasa.

U sljedećem primjeru primijetite što se događa kada promijenimo vrijednost 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"; } } 

Što mislite kakav će biti izlaz? Ako ste pogodili “”, onda vam čestitam! To se događa jer je Stringobjekt nepromjenjiv, što znači da su polja unutar Stringkonačna i da se ne mogu mijenjati.

Ako Stringklasu učinimo nepromjenjivom, dobivamo bolju kontrolu nad jednim od Java najčešće korištenih objekata. Ako bi se vrijednost a Stringmogla promijeniti, to bi stvorilo puno grešaka. Također imajte na umu da ne mijenjamo atribut Stringklase; umjesto toga, jednostavno mu dodjeljujemo novu Stringvrijednost. U tom će se slučaju nameu changeToHomermetodu prenijeti vrijednost "Homer" . String„Homer” će imati pravo da se smeće prikuplja čim changeToHomernačin završi izvršenje. Iako se objekt ne može promijeniti, lokalna varijabla će biti.

Žice i još mnogo toga

Saznajte više o Javinoj Stringklasi i više: Pogledajte sve Rafaelove postove u seriji Java Challengers.

Prolazak referenci promjenjivih objekata

Za razliku od toga String, većina objekata u JDK-u je promjenjiva, poput StringBuilderklase. Primjer u nastavku sličan je prethodnom, ali ima značajke StringBuilderumjesto 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"); } } 

Možete li odrediti izlaz za ovaj primjer? U ovom slučaju, jer radimo s promjenjivim objektom, izlaz će biti "Homer Simpson". Možete očekivati ​​isto ponašanje od bilo kojeg drugog promjenjivog objekta u Javi.

Već ste naučili da se Java varijable prenose prema vrijednosti, što znači da se prosljeđuje kopija vrijednosti. Sjetite se samo da kopirana vrijednost pokazuje na stvarni objekt u hrpi Java memorije. Prolazak pored vrijednosti i dalje mijenja vrijednost stvarnog objekta.

Prihvatite izazov referenci na objekte!

In this Java Challenger we’ll test what you’ve learned about object references. In the code example below, you see the immutable String and the mutable StringBuilder class. Each is being passed as a parameter to a method. Knowing that Java only passes by value, what do you believe will be the output once the main method from this class is executed?

 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; } } 

Here are the options, check the end of this article for the answer key.

A: Warrior=null Weapon=null

B: Warrior=Dragon Weapon=Dragon

C: Warrior=Dragon Knight Weapon=Dragon Sword

D: Warrior=Dragon Knight Weapon=Sword

What’s just happened?

The first parameter in the above example is the warriorProfession variable, which is a mutable object. The second parameter, weapon, is an immutable 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.
  • Mogli biste se iznenaditi kad saznate da su Java primitivni tipovi kontroverzni. U ovoj je značajci John I. Moore obrazložio njihovo čuvanje i učenje kako ih dobro koristiti.
  • Nastavite razvijati svoje vještine programiranja Java u Java Dev Gym-u.
  • Ako vam se svidjelo otklanjanje pogrešaka s Java nasljedstva, pogledajte još videozapisa na popisu za reprodukciju videozapisa Rafael's Java Challenges (videozapisi iz ove serije nisu povezani s JavaWorldom).
  • Želite raditi na projektima bez stresa i pisati kod bez grešaka? Idite na NoBugsProject za svoju kopiju No Bugs, No Stress - Stvorite softver koji mijenja život bez uništavanja vašeg života .

Ova priča "Prolazi li Java referencom ili vrijednošću?" izvorno je objavio JavaWorld.