Går Java med referens eller passerar värde?
Många programmeringsspråk tillåter överföring av parametrar genom referens eller värde . I Java kan vi bara skicka parametrar efter värde . Detta ställer vissa gränser och väcker också frågor. Till exempel, om parametervärdet ändras i metoden, vad händer med värdet efter metodkörning? Du kanske också undrar hur Java hanterar objektvärden i minneshögen. Denna Java Challenger hjälper dig att lösa dessa och andra vanliga frågor om objektreferenser i Java.
Hämta källkoden
Hämta koden för denna Java Challenger. Du kan köra dina egna tester medan du följer exemplen.
Objektreferenser skickas efter värde
Alla objektreferenser i Java skickas efter värde. Detta innebär att en kopia av värdet skickas till en metod. Men tricket är att att skicka en kopia av värdet också ändrar objektets verkliga värde. För att förstå varför, börja med det här exemplet:
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; }
Vad tror du simpson.name
kommer att vara efter att transformIntoHomer
metoden har körts?
I det här fallet blir det Homer! Anledningen är att Java-objektvariabler helt enkelt är referenser som pekar på riktiga objekt i minneshög. Därför ändras även det verkliga objektet, även om Java skickar parametrar till metoder efter värde, om variabeln pekar på en objektreferens.
Om du fortfarande inte är helt klar över hur detta fungerar, ta en titt på figuren nedan.

Passeras primitiva typer av värde?
Liksom objekttyper skickas också primitiva typer av värde. Kan du härleda vad som händer med de primitiva typerna i följande kodexempel?
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; } }
Om du bestämde att värdet skulle ändras till 30, har du rätt. Det är 30 eftersom (igen) Java skickar objektparametrar efter värde. Siffran 30 är bara en kopia av värdet, inte det verkliga värdet. Primitiva typer tilldelas i stackminnet, så endast det lokala värdet kommer att ändras. I det här fallet finns det ingen objektreferens.
Passerar oföränderliga objektreferenser
Vad händer om vi gjorde samma test med ett oföränderligt String
objekt?
JDK innehåller många oföränderliga klasser. Exempel innefattar omslagstyper Integer
, Double
, Float
, Long
, Boolean
, BigDecimal
, och naturligtvis mycket välkänd String
klass.
Lägg märke till vad som händer när vi ändrar värdet på a i nästa exempel 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"; } }
Vad tror du att produktionen blir? Om du gissade “” så grattis! Det händer för att ett String
objekt är oföränderligt, vilket innebär att fälten inuti String
är slutgiltiga och inte kan ändras.
Att göra String
klassen oföränderlig ger oss bättre kontroll över ett av Java mest använda objekt. Om värdet på a String
kunde ändras skulle det skapa många buggar. Observera också att vi inte ändrar ett attribut för String
klassen; istället tilldelar vi det helt enkelt ett nytt String
värde. I detta fall överförs "Homer" -värdet till name
i changeToHomer
metoden. Den String
”Homer” kommer att vara berättigade att skräp samlas så snart changeToHomer
metoden slutför utförande. Även om objektet inte kan ändras kommer den lokala variabeln att vara.
Strängar och mer
Lär dig mer om Javas String
klass och mer: Se alla Rafaels inlägg i Java Challengers-serien.
Passerar muterbara objektreferenser
Till skillnad från String
, de flesta objekt i JDK är mutabla, som StringBuilder
klassen. Exemplet nedan liknar det föregående, men har StringBuilder
snarare än 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"); } }
Kan du dra slutsatsen för detta exempel? I det här fallet, eftersom vi arbetar med ett föränderligt objekt, kommer utmatningen att vara "Homer Simpson." Du kan förvänta dig samma beteende från alla andra föränderliga objekt i Java.
Du har redan lärt dig att Java-variabler skickas efter värde, vilket innebär att en kopia av värdet skickas. Kom bara ihåg att det kopierade värdet pekar på ett riktigt objekt i Java-minneshögen. Att passera med värde ändrar fortfarande värdet på det verkliga objektet.
Ta objektreferensutmaningen!
I den här Java Challenger testar vi vad du har lärt dig om objektreferenser. I kodexemplet nedan ser du den oföränderliga String
och den muterbara StringBuilder
klassen. Varje skickas som en parameter till en metod. Att veta att Java bara passerar med värde, vad tror du kommer att vara resultatet när huvudmetoden från den här klassen har körts?
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; } }
Här är alternativen, kontrollera svarstangenten i slutet av den här artikeln.
A : Krigare = null Vapen = null
B : Warrior = Dragon Weapon = Dragon
C : Warrior = Dragon Knight Weapon = Dragon Sword
D : Warrior = Dragon Knight Weapon = Sword
Vad har just hänt?
Den första parametern i exemplet ovan är warriorProfession
variabeln, som är ett föränderligt objekt. Den andra parametern, vapen, är en oföränderlig 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. - Du kanske blir förvånad över att Java: s primitiva typer är kontroversiella. I den här funktionen gör John I. Moore argument för att behålla dem och lära sig att använda dem väl.
- Fortsätt bygga dina Java-programmeringskunskaper i Java Dev Gym.
- Om du gillade felsökning av Java-arv, kolla in fler videor i Rafaels Java-utmaningar-videospellista (videor i denna serie är inte anslutna till JavaWorld).
- Vill du arbeta med stressfria projekt och skriva felfri kod? Gå över till NoBugsProject för din kopia av No Bugs, No Stress - Skapa livsförändrande programvara utan att förstöra ditt liv .
Denna berättelse, "Går Java genom referens eller skickas med värde?" publicerades ursprungligen av JavaWorld.