1. Референтни променливи
В езика Java има два вида променливи: примитивни променливи и всичко останало. Както се случва, сега ще говорим за „всичко останало“.
Всъщност би било по-правилно да се каже, че има примитивни променливи и референтни променливи . И така, Howви са тези референтни променливи?
За разлика от примитивните типове, чиито променливи съхраняват стойности директно, референтните променливи съхраняват препратки към обекти. Тоест има обект някъде в паметта и референтната променлива просто съхранява address на този обект в паметта (препратка към обекта).
Само примитивните типове съхраняват стойности директно в променливи. Всички други типове съхраняват само препратка към обект . Между другото, вече сте се сблъсквали с два такива типа променливи - String
променливи и променливи с масив .
Както масивът, така и низът са обекти, съхранявани някъде в паметта. String
променливите и масивните променливи съхраняват само препратки към обекти.
int a, int b and double d
са примитивни променливи, които съхраняват своите стойности вътре в себе си.
Променливата String str
е препратка и съхранява address (препратката) към String
обект в паметта.
При присвояване на примитивна стойност на променлива от примитивен тип, нейната стойност се копира (дублира). При присвояване на референтна променлива се копира само addressът на обекта — самият обект не се копира .
2. Какво представляват референциите?
Каква е фундаменталната разлика между референтните променливи и примитивните променливи?
Примитивната променлива е като кутия: можете да съхранявате няHowва стойност в нея. Референтната променлива е по-скоро като лист хартия с телефонен номер върху него.
Кола срещу ключове за кола
Представете си, че сте решor да подарите на приятел кола за рождения му ден. Няма да го увиете в кутия и да го носите със себе си: колата е твърде голяма за това.
Много по-удобно е да поднесете само ключовете за колата в достатъчно голяма кутия, за да ги поберете. Вашият приятел ще разбере всичко, когато извади ключовете от кутията. Няма нужда да носите цялата кола със себе си, когато можете просто да предадете ключовете.
Човек срещу нейния телефонен номер
Или ето още едно сравнение: човек и телефонният му номер. Телефонният номер не е лицето, но телефонният номер може да се използва, за да й се обадите, да я попитате за няHowва информация or да й дадете инструкции.
По същия начин препратката се използва за взаимодействие с обект. Всички обекти взаимодействат помежду си чрез препратки. Вместо да си "разменяме хора", просто си разменяме телефонни номера.
При присвояване на стойност на примитивна променлива, нейната стойност се копира (дублира). При присвояване на стойност на референтна променлива се копира само addressът (телефонният номер) на обекта — самият обект не се копира.
Препратката предлага още едно предимство: можете да предадете препратка към обект към няHowъв метод и методът ще може да модифицира (промени) обекта, като използва препратката към него, извиквайки неговите методи и осъществявайки достъп до данни в обекта.
3. Задаване на справки
При присвояване на референтни променливи се присвоява само addressът на обекта в паметта. Самите обекти не се появяват и не изчезват.
Този подход избягва копирането на големи количества памет. Ако трябва да предадете много голям обект към метод, ние просто предаваме препратката към обекта и това е всичко. Справката заема много по-малко място.
Размерът на всички референтни променливи (независимо от техния тип) е еднакъв — 4 byteа (като int). Но! Ако вашето приложение работи на 64-битова Java машина, тогава всички препратки ще бъдат с размер 8 byteа (64 бита).
Нещо повече, препратките могат да се присвояват само една на друга. Не можете да променяте референции or да присвоявате произволни стойности на референтни променливи:
Код | Описание |
---|---|
|
Това е разрешено |
|
Но това не е позволено |
|
А това не е позволено |
4. null
Справка
И Howво съхранява референтната променлива, ако все още нищо не й е присвоено?
Той съхранява нулева препратка. null
е специална ключова дума в Java, означаваща липсата на препратка (празна препратка). Стойността null
може да бъде присвоена на всяка референтна променлива.
Всички референтни променливи са null
, освен ако не им е присвоена няHowва референция.
Примери:
Код | Описание |
---|---|
|
Променливата String name има стойност по подразбиране: null . Променливата int age има стойност по подразбиране: 0 . |
Локалните променливи, на които не е присвоена стойност, се считат за неинициализирани Howто за примитивните, така и за референтните типове.
Ако променлива съхранява препратка към няHowъв обект и искате да изчистите стойността на променливата, тогава просто й присвоете нулева препратка.
Код | Описание |
---|---|
|
s магазини null . s съхранява препратка към низов обект s съхранява null . |
5. Предаване на препратки към методи
Ако даден метод има параметри, които са референтни типове , тогава стойностите се предават на метода по същия начин, Howто при работа с нереферентни променливи. На параметъра просто се присвоява стойността на другата променлива.
Пример:
Код | Описание |
---|---|
|
Запълва fill подавания масив ( array ) с подадената стойност ( value ). |
Когато fill
методът се извика, на array
параметъра се присвоява препратка към data
масива. На value
променливата се присвоява препратка към низовия обект ("Hello").
Ето How изглежда паметта преди извикване на fill
метода:
Ето How изглежда паметта, когато fill
методът се изпълнява :
Променливите data
и array
се отнасят до (съхраняват препратки към) същия контейнер в паметта.
Променливата value
съхранява препратка към низовия обект ( "Hello"
).
Клетките на масива също само съхраняват препратки към "Hello"
обекта.
Всъщност ниHowви обекти не се дублират - само препратките се копират.
6. Сравнение с езика C/C++
В интервюта понякога Java програмистите биват питани How данните се предават на методи в Java? И понякога въпросът е дали данните се предават по референция or по стойност?
Този въпрос идва от C++, но не е много смислен в Java . В Java на параметрите винаги се присвояват просто стойностите на аргументите. Така че правилният отговор би бил " по стойност ".
Но бъдете готови да обясните позицията си , тъй като може веднага да чуете репликата: "примитивните типове се предават по стойност, а референтните типове се предават по референция."
Този произход на този проблем произтича от факта, че много Java програмисти са бor C++ програмисти в миналото. В този език за програмиране въпросът How параметрите се предават на методите беше много важен.
В Java всичко е недвусмислено: примитивните типове съхраняват стойности и референтните типове също съхраняват стойност - референция. Въпросът е дали една променлива се счита за стойност .
В C++ една променлива може да съхранява Howто препратка към обект, така и самия обект. Същото важи и за примитивните типове: примитивна променлива може да съхранява стойност or да декларира променливата като препратка към int
. Така че, за да избегнат объркване, C++ програмистите винаги се отнасят към обекта към референция като референция , а самия обект — като стойност.
В C++ можете лесно да имате ситуация, в която една променлива съдържа обект, но другата съдържа препратка към този обект. Съответно, въпросът Howво съхранява една променлива - самия обект or просто препратка към него - беше много важен. Когато даден обект е предаден на метод, той е копиран (ако е предаден по стойност) и не е копиран (ако е предаден чрез препратка).
В Java тази двойственост не съществува, така че правилният отговор е: аргументите се предават на методите на Java по стойност . Просто когато говорим за референтни променливи, тази стойност е референтна.
GO TO FULL VERSION