1. Mga sanggunian na variable

Sa wikang Java, mayroong dalawang uri ng mga variable: primitive variable at lahat ng iba pa. Habang nangyayari ito, pag-uusapan natin ngayon ang tungkol sa "lahat ng iba pa".

Sa katunayan, mas tamang sabihin na mayroong mga primitive na variable at reference na variable . Kaya ano ang mga sangguniang variable na ito?

Hindi tulad ng mga primitive na uri, na ang mga variable ay direktang nag-iimbak ng mga halaga, ang mga reference na variable ay nag-iimbak ng mga reference sa mga bagay. Iyon ay, mayroong isang bagay sa isang lugar sa memorya, at ang reference variable ay nag-iimbak lamang ng address ng bagay na ito sa memorya (isang reference sa object).

Ang mga primitive na uri lamang ang nag-iimbak ng mga halaga nang direkta sa loob ng mga variable. Ang lahat ng iba pang uri ay nag-iimbak lamang ng isang object reference . Siyanga pala, nakatagpo ka na ng dalawang ganoong uri ng mga variable — Stringmga variable at array variable.

Parehong isang array at isang string ay mga bagay na nakaimbak sa isang lugar sa memorya. Stringang mga variable at array variable ay nag-iimbak lamang ng mga sanggunian sa mga bagay.

Mga sanggunian na variable sa Java

int a, int b and double day mga primitive na variable na nag-iimbak ng kanilang mga halaga sa loob ng kanilang sarili.

Ang String strvariable ay isang reference at iniimbak ang address (reference) sa isang Stringobject sa memorya.

Kapag nagtatalaga ng primitive na halaga sa isang variable ng primitive na uri, ang halaga nito ay kinopya (doble). Kapag nagtatalaga ng reference variable, tanging ang address ng object ang kinokopyaang object mismo ay hindi kinopya .


2. Tungkol saan ang mga sanggunian?

Ano ang pangunahing pagkakaiba sa pagitan ng mga sangguniang variable at primitive na mga variable?

Ang isang primitive na variable ay tulad ng isang kahon: maaari kang mag-imbak ng ilang halaga dito. Ang isang reference variable ay mas katulad ng isang piraso ng papel na may numero ng telepono dito.

Isang kotse vs susi sa kotse

Isipin na nagpasya kang bigyan ang iyong kaibigan ng kotse para sa kanyang kaarawan. Hindi mo ito ibalot sa isang kahon at dadalhin mo: ang kotse ay masyadong malaki para doon.

Ito ay mas maginhawa upang ipakita lamang ang mga susi ng kotse sa isang kahon na sapat na malaki upang maglaman ng mga ito. Mauunawaan ng iyong kaibigan ang lahat kapag nakuha niya ang mga susi sa kahon. Hindi na kailangang dalhin ang buong kotse kapag maaari mong ibigay ang mga susi.

Isang tao laban sa kanyang numero ng telepono

O narito ang isa pang paghahambing: isang tao at ang kanyang numero ng telepono. Ang isang numero ng telepono ay hindi ang tao, ngunit ang isang numero ng telepono ay maaaring gamitin upang tawagan siya, humingi sa kanya ng ilang impormasyon, o magbigay ng mga tagubilin.

Katulad nito, ang isang sanggunian ay ginagamit upang makipag-ugnayan sa isang bagay. Ang lahat ng mga bagay ay nakikipag-ugnayan sa isa't isa gamit ang mga sanggunian. Sa halip na "magpalitan ng tao", nagpapalitan na lang kami ng mga numero ng telepono.

Kapag nagtatalaga ng isang halaga sa isang primitive na variable, ang halaga nito ay kinokopya (doble). Kapag nagtatalaga ng value sa isang reference na variable, tanging ang address (numero ng telepono) ng object ang kinokopya — ang object mismo ay hindi kinokopya.

Ang isang sanggunian ay nag-aalok ng isa pang kalamangan: maaari kang magpasa ng isang sanggunian ng bagay sa ilang pamamaraan, at ang pamamaraan ay magagawang baguhin (baguhin) ang bagay sa pamamagitan ng paggamit ng sanggunian dito, pagtawag sa mga pamamaraan nito at pag-access ng data sa loob ng bagay.


3. Pagtatalaga ng mga sanggunian

Kapag nagtatalaga ng mga reference na variable, tanging ang address ng object sa memorya ang itinalaga. Ang mga bagay mismo ay hindi lumilitaw o nawawala.

Iniiwasan ng diskarteng ito ang pagkopya ng malaking halaga ng memorya. Kung kailangan mong ipasa ang isang napakalaking bagay sa isang pamamaraan, ipapasa lang namin ang object reference at iyon na. Ang sanggunian ay tumatagal ng mas kaunting espasyo.

Pagtatalaga ng mga sanggunian

Ang laki ng lahat ng reference na variable (anuman ang uri nito) ay pareho — 4 bytes (tulad ng int). Ngunit! Kung tumatakbo ang iyong application sa isang 64-bit na Java machine, ang lahat ng reference ay magiging 8 byte (64 bits) ang laki.

Higit pa rito, ang mga sanggunian ay maaari lamang italaga sa isa't isa. Hindi mo maaaring baguhin ang mga reference o magtalaga ng mga arbitrary na halaga sa mga reference na variable:

Code Paglalarawan
String hello = "Hello";
String s = hello;
Ito ay pinapayagan
String hello = "Hello";
hello++;
Ngunit ito ay hindi pinapayagan
String hello = 0x1234;
At ito ay hindi pinapayagan

4. Isang nullsanggunian

At ano ang iniimbak ng isang reference variable kung wala pang nakatalaga dito?

Nag-iimbak ito ng null reference. nullay isang espesyal na keyword ng Java na nangangahulugan ng kawalan ng isang sanggunian (isang walang laman na sanggunian). nullMaaaring italaga ang halaga sa anumang reference na variable.

Ang lahat ng mga reference na variable ay nullmaliban kung mayroon silang ilang uri ng reference na itinalaga sa kanila.

Mga halimbawa:

Code Paglalarawan
class Person
{
   public static String name;
   public static int age;
}


Ang String namevariable ay may default na halaga: null.
Ang int agevariable ay may default na halaga: 0.

Ang mga lokal na variable na hindi naitatalaga ng isang halaga ay itinuturing na hindi nasimulan para sa parehong mga primitive at reference na uri.

Kung ang isang variable ay nag-iimbak ng isang reference sa ilang bagay, at gusto mong i-clear ang halaga ng variable, pagkatapos ay italaga lamang ito ng isang null reference.

Code Paglalarawan
String s = null;
s = "Hello";
s = null;
smga tindahan null.
snag-iimbak ng isang sanggunian sa isang string object
sna nag-iimbak null.

5. Pagpasa ng mga sanggunian sa mga pamamaraan

Kung ang isang pamamaraan ay may mga parameter na mga uri ng sanggunian , ang mga halaga ay ipinapasa sa pamamaraan sa parehong paraan tulad ng kapag nagtatrabaho sa mga di-reference na variable. Ang parameter ay itinalaga lamang ang halaga ng iba pang variable.

Halimbawa:

Code Paglalarawan
class Solution
{
   public static void fill(String[] array, String value)
   {
      for (int i = 0; i < array.length; i++)
        array[i] = value;
   }

   public static void main(String[] args)
   {
     String[] data = new String[10];
     fill(data, "Hello");
   }
}


Pinupuan ng fillnaipasa na array ( array) ang naipasa na halaga ( value).

Kapag filltinawag ang pamamaraan, ang arrayparameter ay itinalaga ng isang sanggunian sa dataarray. Ang valuevariable ay itinalaga ng isang reference sa string object ("Hello").

Ito ang hitsura ng memorya bago tawagan ang fill pamamaraan:

Pagpasa ng mga sanggunian sa mga pamamaraan

Ito ang hitsura ng memorya kapag fill tumatakbo ang pamamaraan :

Pagpasa ng mga sanggunian sa mga pamamaraan 2

Ang dataat arraymga variable ay tumutukoy sa (mga store reference sa) sa parehong lalagyan sa memorya.

Ang valuevariable ay nag-iimbak ng reference sa string object ( "Hello").

Ang mga cell ng array ay nag-iimbak lamang ng mga sanggunian sa "Hello"bagay.

Sa katunayan, walang mga bagay na nadoble — tanging mga sanggunian lamang ang kinokopya.



6. Paghahambing sa wikang C/C ++

Sa mga panayam, minsan tinatanong ang mga programmer ng Java kung paano ipinapasa ang data sa mga pamamaraan sa Java? At kung minsan ang tanong ay kung ang data ay ipinasa sa pamamagitan ng sanggunian o sa pamamagitan ng halaga?

Ang tanong na ito ay nagmula sa C++, ngunit hindi masyadong makabuluhan sa Java . Sa Java, ang mga parameter ay palaging itinatalaga lamang ang mga halaga ng mga argumento. Kaya ang tamang sagot ay " ayon sa halaga ".

Ngunit maging handa na ipaliwanag ang iyong posisyon , dahil maaari mong marinig kaagad ang sagot: "Ang mga primitive na uri ay ipinapasa sa pamamagitan ng halaga, at ang mga uri ng sanggunian ay ipinapasa sa pamamagitan ng sanggunian."

Ang pinagmulan ng isyung ito ay nagmumula sa katotohanang maraming Java programmer ang C++ programmer sa nakaraan. Sa programming language na iyon, ang tanong kung paano ipinapasa ang mga parameter sa mga pamamaraan ay napakahalaga.

Sa Java, ang lahat ay hindi malabo: ang mga primitive na uri ay nag-iimbak ng mga halaga at mga uri ng sanggunian ay nag-iimbak din ng isang halaga — isang reference. Ito ay isang tanong kung ang isang variable ay itinuturing na isang halaga .

Sa C++, maaaring mag-imbak ang isang variable ng isang sanggunian sa isang bagay at sa mismong bagay. Ang parehong ay totoo tungkol sa mga primitive na uri: ang isang primitive na variable ay maaaring mag-imbak ng isang halaga o magpahayag ng variable bilang isang reference sa isang int. Kaya, upang maiwasan ang pagkalito, palaging tinutukoy ng mga programmer ng C++ ang object sa isang reference bilang isang reference , at ang object mismo — bilang isang value.

Sa C++, madali kang magkaroon ng sitwasyon kung saan ang isang variable ay naglalaman ng isang bagay, ngunit ang isa ay naglalaman ng isang sanggunian sa bagay na iyon. Alinsunod dito, ang tanong kung ano ang iniimbak ng isang variable — ang bagay mismo o isang sanggunian lamang dito — ay napakahalaga. Kapag ang isang bagay ay naipasa sa isang pamamaraan, ito ay kinopya (kung ipinasa sa pamamagitan ng halaga), at hindi kinopya (kung ipinasa sa pamamagitan ng sanggunian).

Sa Java, ang duality na ito ay hindi umiiral, kaya ang tamang sagot ay: ang mga argumento ay ipinapasa sa mga pamamaraan ng Java sa pamamagitan ng halaga . Kaya lang kapag pinag-uusapan natin ang mga reference variable, ang value na ito ay isang reference.