Много езици за програмиране позволяват предаване на параметри по референция или по стойност . В Java можем да предаваме параметри само по стойност . Това налага някои ограничения и също така повдига въпроси. Например, ако стойността на параметъра се промени в метода, какво се случва със стойността след изпълнението на метода? Може също да се чудите как Java управлява обектни стойности в купчината памет. Този Java Challenger ви помага да разрешите тези и други често срещани въпроси относно препратките към обекти в Java.
Вземете изходния код
Вземете кода за този Java Challenger. Можете да провеждате свои собствени тестове, докато следвате примерите.
Препратките към обекти се предават по стойност
Всички препратки към обекти в Java се предават по стойност. Това означава, че копие на стойността ще бъде предадено на метод. Но трикът е, че предаването на копие на стойността променя и реалната стойност на обекта. За да разберете защо, започнете с този пример:
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; }
Какво мислите, че simpson.name
ще бъде след изпълнението на transformIntoHomer
метода?
В този случай това ще бъде Омир! Причината е, че Java обектните променливи са просто препратки, които сочат към реални обекти в купчината памет. Следователно, въпреки че Java предава параметри на методи по стойност, ако променливата сочи към препратка към обект, реалният обект също ще бъде променен.
Ако все още не сте съвсем наясно как става това, погледнете фигурата по-долу.

Примитивните типове предават ли се по стойност?
Подобно на типовете обекти, примитивните типове също се предават по стойност. Можете ли да разберете какво ще се случи с примитивните типове в следващия пример на код?
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; } }
Ако сте решили, че стойността ще се промени на 30, вие сте прави. Това е 30, защото (отново) Java предава параметрите на обекта по стойност. Числото 30 е просто копие на стойността, а не реалната стойност. Примитивните типове са разпределени в паметта на стека, така че само локалната стойност ще бъде променена. В този случай няма препратка към обект.
Предаване на неизменяеми препратки към обекти
Ами ако направим същия тест с неизменяем String
обект?
JDK съдържа много неизменни класове. Примерите включват видовете обвивки Integer
, Double
, Float
, Long
, Boolean
, BigDecimal
, и, разбира се, много добре известен String
клас.
В следващия пример забележете какво се случва, когато променим стойността на 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"; } }
Какъв според вас ще бъде изходът? Ако познахте “”, тогава поздравления! Това се случва, защото String
обектът е неизменим, което означава, че полетата вътре в String
са окончателни и не могат да бъдат променяни.
Осъществяването на String
класа неизменяем ни дава по-добър контрол над един от най-използваните обекти на Java. Ако стойността на a String
може да бъде променена, това би създало много грешки. Също така имайте предвид, че не променяме атрибут на String
класа; вместо това просто му присвояваме нова String
стойност. В този случай стойността “Homer” ще бъде предадена name
в changeToHomer
метода. В String
"Омир" ще могат да кандидатстват за боклук събран веднага след като changeToHomer
метод завършва изпълнение. Въпреки че обектът не може да бъде променен, локалната променлива ще бъде.
Струни и др
Научете повече за String
класа на Java и още: Вижте всички публикации на Рафаел в поредицата Java Challengers.
Предаване на променливи препратки към обекти
За разлика от това String
, повечето обекти в JDK са променливи, като StringBuilder
класа. Примерът по-долу е подобен на предишния, но има функции, StringBuilder
а не 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"); } }
Можете ли да изведете резултата за този пример? В този случай, тъй като работим с изменяем обект, изходът ще бъде „Homer Simpson“. Можете да очаквате същото поведение от всеки друг изменяем обект в Java.
Вече научихте, че променливите Java се предават по стойност, което означава, че се предава копие на стойността. Само не забравяйте, че копираната стойност сочи към реален обект в купчината памет на Java. Преминаването по стойност все още променя стойността на реалния обект.
Приемете предизвикателството за препратки към обекти!
В този Java Challenger ще тестваме какво сте научили за препратките към обекти. В примера на кода по-долу виждате неизменяем String
и изменяем StringBuilder
клас. Всеки се предава като параметър на метод. Знаейки, че Java преминава само по стойност, какво според вас ще бъде изходът, след като се изпълни основният метод от този клас?
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; } }
Ето опциите, проверете края на тази статия за ключ за отговор.
A : Warrior = null Оръжие = null
Б : Воин = Драконово оръжие = Дракон
В : Воин = Оръжие на рицар-дракон = Драконов меч
D : Воин = Оръжие на рицар-дракон = Меч
Какво точно се случи?
Първият параметър в горния пример е warriorProfession
променливата, която е променлив обект. Вторият параметър, оръжието, е неизменим 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. - Може да се изненадате да разберете, че примитивните типове Java са противоречиви. В тази функция Джон И. Мур обосновава запазването им и ученето да ги използва добре.
- Продължавайте да изграждате своите умения за програмиране на Java в Java Dev Gym.
- Ако ви е харесало отстраняването на грешки в наследяването на Java, разгледайте още видеоклипове в плейлиста за видео предизвикателства на Java на Rafael (видеоклипове от тази поредица не са свързани с JavaWorld).
- Искате ли да работите по проекти без стрес и да пишете код без грешки? Насочете се към NoBugsProject за вашето копие на No Bugs, No Stress - Създайте променящ живота софтуер, без да унищожавате живота си .
Тази история, "Предава ли Java препратка или предава стойност?" е първоначално публикуван от JavaWorld.