Vrijednost prosljeđivanja kao mehanizam prolaska parametara u Javi

1. Uvod

Dva najrasprostranjenija načina prosljeđivanja argumenata metodama su "prosljeđivanje vrijednosti" i "prolaženje referencom". Različiti programski jezici koriste ove koncepte na različite načine. Što se Jave tiče, sve je strogo Prolazna vrijednost.

U ovom uputstvu ilustrirat ćemo kako Java prenosi argumente za razne tipove.

2. Pass-by-Value vs Pass-by-Reference

Počnimo s nekim od različitih mehanizama za prosljeđivanje parametara funkcijama:

  • vrijednost
  • referenca
  • proizlaziti
  • vrijednost-rezultat
  • Ime

Dva najčešća mehanizma u modernim programskim jezicima su "Pass-by-Value" i "Pass-by-Reference". Prije nego što nastavimo, prvo razgovarajmo o sljedećim:

2.1. Prolazna vrijednost

Kada je parametar prolazna vrijednost, pozivatelj i metoda pozivatelja djeluju na dvije različite varijable koje su međusobne kopije. Bilo kakve promjene jedne varijable ne mijenjaju drugu.

To znači da dok zovete metodu, parametri prosljeđeni metodi poziva bit će klonovi izvornih parametara. Svaka izmjena izvršena u metodi pozivatelja neće imati utjecaja na izvorne parametre u metodi pozivatelja.

2.2. Referenca za prolaz

Kada je parametar referenca prolaznog poziva, pozivalac i pozivani djeluju na istom objektu.

To znači da kada je varijabla prolazna referenca, jedinstveni identifikator objekta šalje se metodi. Sve promjene članova instance parametra rezultirat će promjenom izvorne vrijednosti.

3. Prolazak parametara u Javi

Temeljni pojmovi u bilo kojem programskom jeziku su "vrijednosti" i "reference". U Javi, Primitivne varijable pohranjuju stvarne vrijednosti, dok neprimitivne pohranjuju referentne varijable koje upućuju na adrese objekata na koje se odnose. I vrijednosti i reference pohranjene su u memoriji stoga.

Argumenti u Javi uvijek se prosljeđuju. Tijekom pozivanja metode stvara se kopija svakog argumenta, bilo da je to vrijednost ili referenca, u memoriji stoga koja se zatim prenosi metodi.

U slučaju primitiva, vrijednost se jednostavno kopira u memoriju steka koja se zatim prenosi na metodu pozivanja; u slučaju neprimitiva, referenca u memoriji stoga ukazuje na stvarne podatke koji se nalaze u hrpi. Kad proslijedimo objekt, referenca u memoriji steka se kopira, a nova referenca prosljeđuje metodi.

Pogledajmo sada to na djelu uz pomoć nekih primjera koda.

3.1. Prolazak primitivnih tipova

Programski jezik Java sadrži osam primitivnih vrsta podataka. Primitivne varijable izravno se pohranjuju u memoriju stoga. Kad god se bilo koja varijabla primitivnog tipa podataka preda kao argument, stvarni se parametri kopiraju u formalne argumente i ti formalni argumenti akumuliraju vlastiti prostor u memoriji stoga.

Životni vijek ovih formalnih parametara traje samo dok se ta metoda izvodi, a po povratku ti se formalni argumenti uklanjaju iz hrpe i odbacuju.

Pokušajmo to razumjeti uz pomoć primjera koda:

javna klasa PrimitiveUnitTest {@Test public void whenModifyingPrimitive_thenOriginalValuesNotModified () {int x = 1; int y = 2; // Prije modifikacije assertEquals (x, 1); assertEquals (y, 2); modificirati (x, y); // Nakon izmjene assertEquals (x, 1); assertEquals (y, 2); } javna statička praznina modificirati (int x1, int y1) {x1 = 5; y1 = 10; }} 

Pokušajmo razumjeti tvrdnje u gornjem programu analizirajući kako su te vrijednosti pohranjene u memoriji:

  1. Varijable „x" i "y " u glavnoj su metodi primitivni tipovi i njihove se vrijednosti izravno pohranjuju u memoriju stoga
  2. Kad zovemo metodu izmijeniti (), stvara se točna kopija za svaku od ovih varijabli koja se pohranjuje na različito mjesto u memoriji stoga
  3. Svaka izmjena ovih kopija utječe samo na njih i ostavlja izvorne varijable nepromijenjenima

3.2. Prosljeđivanje referenci objekata

U Javi su svi objekti dinamički pohranjeni u Heap prostoru ispod haube. Ti se objekti upućuju iz referenci koje se nazivaju referentne varijable.

Java objekt, za razliku od primitiva, pohranjuje se u dvije faze. Referentne varijable pohranjene su u memoriji stoga, a objekt na koji se pozivaju pohranjen je u hrpu memorije.

Kad god se objekt preda kao argument, kreira se točna kopija referentne varijable koja upućuje na isto mjesto objekta u memoriji hrpe kao i izvorna referentna varijabla.

Kao rezultat toga, kad god napravimo bilo kakvu promjenu na istom objektu u metodi, ta se promjena odražava na izvornom objektu. Međutim, ako dodijelimo novi objekt prosljeđenoj referentnoj varijabli, tada se to neće odraziti na izvornom objektu.

Pokušajmo to shvatiti uz pomoć primjera koda:

javna klasa NonPrimitiveUnitTest {@Test public void whenModifyingObjects_thenOriginalObjectChanged () {Foo a = new Foo (1); Foo b = novi Foo (1); // Prije modifikacije assertEquals (a.num, 1); assertEquals (b.num, 1); izmijeniti (a, b); // Nakon izmjene assertEquals (a.num, 2); assertEquals (b.num, 1); } javna statička praznina izmijeniti (Foo a1, Foo b1) {a1.num ++; b1 = novi Foo (1); b1.num ++; }} klasa Foo {javni int num; javni Foo (int num) {this.num = num; }}

Analizirajmo tvrdnje iz gornjeg programa. Prošli smo predmete a i b u izmijeniti () metoda koja ima istu vrijednost 1. U početku ove reference objekata upućuju na dva različita mjesta objekta u prostoru hrpe:

Kad ove reference a i b prenose se u izmijeniti () metodom, stvara zrcalne kopije tih referenci a1 i b1 koji upućuju na iste stare predmete:

U izmijeniti () metodom, kada mijenjamo referencu a1, mijenja izvorni objekt. Međutim, za referencu b1, dodijelili smo novi objekt. Dakle, sada pokazuje na novi objekt u memoriji hrpe.

Svaka promjena u b1 neće odražavati ništa u izvornom objektu:

4. Zaključak

U ovom smo članku pogledali kako se postupa s prosljeđivanjem parametara u slučaju primitiva i neprimitiva.

Saznali smo da je dodavanje parametara u Javi uvijek prolazna vrijednost. Međutim, kontekst se mijenja ovisno o tome imamo li posla s primitivima ili objektima:

  1. Za primitivne tipove, parametri su prolazne vrijednosti
  2. Za tipove objekata referenca na objekt je prolazna vrijednost

Isječci koda korišteni u ovom članku mogu se naći na GitHubu.