Ohjelmointi

Kulkeeko Java viitteenä vai arvon mukaan?

Monet ohjelmointikielet sallivat parametrien välittämisen viitteellä tai arvolla. Java-ohjelmassa voimme välittää vain parametreja arvon mukaan. Tämä asettaa joitain rajoja ja herättää myös kysymyksiä. Esimerkiksi jos parametrin arvoa muutetaan menetelmässä, mitä tapahtuu menetelmän suorituksen jälkeiselle arvolle? Saatat myös miettiä, kuinka Java hallitsee objektiarvoja muistihunassa. Tämä Java Challenger auttaa ratkaisemaan nämä ja muut Java-objektiviittauksiin liittyvät yleiset kysymykset.

Hanki lähdekoodi

Hanki koodi tälle Java Challengerille. Voit suorittaa omia testejä samalla kun noudatat esimerkkejä.

Objektiviitteet välitetään arvon mukaan

Kaikki Java-objektiviittaukset välitetään arvon mukaan. Tämä tarkoittaa, että kopio arvosta välitetään menetelmälle. Mutta temppu on, että arvon kopion välittäminen muuttaa myös kohteen todellista arvoa. Aloita tästä esimerkistä ymmärtääksesi miksi:

 public class ObjectReferenceExample {public static void main (String ... doYourBest) {Simpson simpson = uusi Simpson (); transformIntoHomer (simpson); System.out.println (simpson.nimi); } staattinen void transformIntoHomer (Simpson simpson) {simpson.name = "Homer"; }} luokka Simpson {String name; } 

Mitä luulet simpson.name on jälkeen muunnaHomeriksi menetelmä suoritetaan?

Tässä tapauksessa se on Homer! Syynä on se, että Java-objektimuuttujat ovat yksinkertaisesti viitteitä, jotka viittaavat todellisiin objekteihin muistin kasassa. Siksi, vaikka Java välittää parametrit menetelmille arvon mukaan, jos muuttuja osoittaa objektiviittauksen, myös todellinen objekti muuttuu.

Jos et vieläkään ole täysin selvä, miten tämä toimii, katso alla oleva kuva.

Rafael Chinelato Del Nero

Siirretäänkö primitiiviset tyypit arvon mukaan?

Kuten kohdetyypit, myös primitiiviset tyypit välitetään arvon perusteella. Voitteko seuraavasta koodiesimerkistä päätellä, mitä primitiivityypeille tapahtuu?

 public class PrimitiveByValueExample {public static void main (String ... primitiveByValue) {int homerAge = 30; muutosHomerAge (homerAge); System.out.println (homerAge); } staattinen tyhjiön muutosHomerAge (int homerAge) {homerAge = 35; }} 

Jos päätit, että arvo muuttuisi 30: ksi, olet oikeassa. Se on 30, koska (jälleen) Java välittää objektiparametrit arvon mukaan. Luku 30 on vain kopio arvosta, ei todellinen arvo. Primitiiviset tyypit on varattu pinomuistiin, joten vain paikallista arvoa muutetaan. Tässä tapauksessa objektiviittausta ei ole.

Muuttamattomien objektiohjeiden välittäminen

Entä jos tekisimme saman testin muuttumattomalla Merkkijono esine?

JDK sisältää monia muuttumattomia luokkia. Esimerkkejä ovat käärintätyypit Kokonaisluku, Kaksinkertainen, Kellua, Pitkä, Boolen, BigDecimal, ja tietysti hyvin tunnettu Merkkijono luokassa.

Huomaa seuraavassa esimerkissä, mitä tapahtuu, kun muutamme a: n arvoa Merkkijono.

 public class StringValueChange {public static void main (String ... doYourBest) {String name = ""; changeToHomer (nimi); System.out.println (nimi); } staattinen void changeToHomer (merkkijonon nimi) {name = "Homer"; }} 

Mitä luulet tuotokseksi? Jos arvasit “”, onnittelut! Tämä tapahtuu, koska a Merkkijono objekti on muuttumaton, mikä tarkoittaa, että kentät Merkkijono ovat lopullisia eikä niitä voi muuttaa.

Tekemällä Merkkijono luokan muuttumaton antaa meille paremman hallinnan Javan yleisimmin käytettyihin kohteisiin. Jos arvo a Merkkijono voidaan muuttaa, se loisi paljon vikoja. Huomaa myös, että emme muuta Merkkijono luokka; sen sijaan annamme yksinkertaisesti uuden Merkkijono arvo sille. Tässä tapauksessa Homer-arvo välitetään nimi että vaihda ToHomer menetelmä. Merkkijono "Homer" on oikeutettu keräämään roskia heti vaihda ToHomer menetelmä suorittaa suorituksen loppuun. Vaikka objektia ei voida muuttaa, paikallinen muuttuja on.

Jouset ja paljon muuta

Lisätietoja Java: sta Merkkijono luokka ja paljon muuta: Katso kaikki Rafaelin viestit Java Challengers -sarjassa.

Muuttuvien objektien viitteiden välittäminen

Toisin kuin Merkkijono, useimmat JDK: n objektit ovat muutettavissa, kuten StringBuilder luokassa. Alla oleva esimerkki on samanlainen kuin edellinen, mutta siinä on ominaisuuksia StringBuilder mielummin kuin Merkkijono:

 staattinen luokka MutableObjectReference {public static void main (String ... mutableObjectExample) {StringBuilder-nimi = uusi StringBuilder ("Homer"); addSureName (nimi); System.out.println (nimi); } static void addSureName (StringBuilder-nimi) {name.append ("Simpson"); }} 

Voitteko päätellä tämän esimerkin tuotoksen? Tässä tapauksessa, koska työskentelemme muutettavan objektin kanssa, lähtö on Homer Simpson. Voit odottaa samaa käyttäytymistä kaikilta muilta Java-muuttujilta.

Olet jo oppinut, että Java-muuttujat välitetään arvon mukaan, eli kopio arvosta välitetään. Muista vain, että kopioitu arvo osoittaa a todellinen esine Java-muistin kasaan. Arvon välittäminen muuttaa edelleen todellisen kohteen arvoa.

Ota vastaan ​​objektiviittausten haaste!

Tässä Java Challengerissa testataan, mitä olet oppinut objektiviittauksista. Alla olevassa koodiesimerkissä näet muuttumattoman Merkkijono ja muuttuva StringBuilder luokassa. Jokainen niistä välitetään parametrina menetelmälle. Kun tiedät, että Java kulkee vain arvon perusteella, mikä luulet olevan tulos, kun tämän luokan päämenetelmä on suoritettu?

 public class DragonWarriorReferenceChallenger {public static void main (String ... doYourBest) {StringBuilder warriorProfession = uusi StringBuilder ("Dragon"); Merkkijono warriorWeapon = "Miekka"; changeWarriorClass (soturiProfession, warriorWeapon); System.out.println ("Warrior =" + warriorProfession + "Weapon =" + warriorWeapon); } staattinen void changeWarriorClass (StringBuilder warriorProfession, String-ase) {warriorProfession.append ("Knight"); ase = "Lohikäärme" + ase; ase = tyhjä; warriorProfession = tyhjä; }} 

Tässä ovat vaihtoehdot. Tarkista tämän artikkelin lopusta vastausavain.

A: Warrior = null Ase = null

B: Soturi = Lohikäärmease = Lohikäärme

C: Soturi = Lohikäärmeen ase = Lohikäärmiekka

D.: Soturi = Lohikäärmeen ase = Miekka

Mitä juuri tapahtui?

Yllä olevan esimerkin ensimmäinen parametri on soturiAmmatti muuttuja, joka on muutettava objekti. Toinen parametri, ase, on muuttumaton Merkkijono:

 staattinen void changeWarriorClass (StringBuilder warriorProfession, String-ase) {...} 

Analysoidaan nyt, mitä tämän menetelmän sisällä tapahtuu. Tämän menetelmän ensimmäisellä rivillä lisätään Ritari arvo soturiAmmatti muuttuja. Muista se soturiAmmatti on muutettava kohde; siksi todellinen esine muuttuu, ja sen arvo on “Dragon Knight”.

 warriorProfession.append ("Ritari"); 

Toisessa ohjeessa muuttumaton paikallinen Merkkijono muuttuja muutetaan Dragon Swordiksi. Todellista kohdetta ei kuitenkaan koskaan muuteta siitä lähtien Merkkijono on muuttumaton ja sen ominaisuudet ovat lopullisia:

 ase = "Lohikäärme" + ase; 

Lopuksi ohitamme tyhjä muuttujiin täällä, mutta ei objekteihin. Kohteet pysyvät samoina, kunhan niihin pääsee edelleen ulkoisesti - tässä tapauksessa päämenetelmän kautta. Ja vaikka paikalliset muuttujat ovat nollia, esineille ei tapahdu mitään:

 ase = tyhjä; warriorProfession = tyhjä; 

Kaiken tämän perusteella voimme päätellä, että lopulliset arvot ovat muutettavissa StringBuilder ja muuttumaton Merkkijono tulee olemaan:

 System.out.println ("Warrior =" + warriorProfession + "Weapon =" + warriorWeapon); 

Ainoa arvo, joka muuttui changeWarriorClass menetelmä oli soturiAmmatti, koska se on muutettava StringBuilder esine. Ota huomioon, että soturiAse ei muuttunut, koska se on muuttumaton Merkkijono esine.

Oikea lähtö Challenger-koodistamme olisi:

D.: Soturi = Lohikäärmeen ase = Miekka.

Video-haaste! Objektiviittausten virheenkorjaus Javassa

Virheenkorjaus on yksi helpoimmista tavoista hyödyntää ohjelmointikonsepteja täysin ja parantaa samalla koodiasi. Tässä videossa voit seurata mukana, kun minä virheenkorjaan ja selitän Java-objektiviittauksia.

Objektiviittausten yleiset virheet

  • Yritetään muuttaa muuttumatonta arvoa viitteenä.
  • Yritetään muuttaa primitiivistä muuttujaa viitteenä.
  • Todellisen objektin odottaminen ei muutu, kun muutat muutettavan objektin parametria menetelmässä.

Mitä on muistettava objektiviittauksista

  • Java välittää parametrimuuttujat aina arvon mukaan.
  • Java-objektimuuttujat osoittavat aina muistin kasassa olevan todellisen objektin.
  • Muokattavan objektin arvoa voidaan muuttaa, kun se välitetään menetelmälle.
  • Muuttamattoman kohteen arvoa ei voida muuttaa, vaikka sille välitettäisiin uusi arvo.
  • "Passing by value" tarkoittaa arvon kopion välittämistä.
  • ”Passing by reference” viittaa muuttujan todellisen viitteen välittämiseen muistissa.

Lisätietoja Java-ohjelmasta

  • Hanki lisää nopeita koodivinkkejä: Lue kaikki Rafaelin viestit JavaWorld Java Challengers -sarjasta.
  • Lisätietoja muutettavista ja muuttumattomista Java-objekteista (kuten Merkkijono ja StringBuffer) ja miten niitä käytetään koodissasi.
  • Saatat olla yllättynyt kuullessasi, että Java: n primitiiviset tyypit ovat kiistanalaisia. Tässä ominaisuudessa John I.Moore antaa aiheen pitää heidät ja oppia käyttämään niitä hyvin.
  • Rakenna Java-ohjelmointitaitojasi Java Dev Gym -keskuksessa.
  • Jos pidit Java-perinnön virheenkorjauksesta, katso lisää videoita Rafaelin Java Challenges -videosoittolistalta (tämän sarjan videot eivät ole yhteydessä JavaWorldiin).
  • Haluatko työskennellä stressittömissä projekteissa ja kirjoittaa virheetöntä koodia? Siirry NoBugsProjectiin kopiossasi Ei vikoja, ei stressiä - luo elämää muuttava ohjelmisto tuhoamatta elämääsi.

Tämä tarina "kulkee Java viitteenä vai arvon kautta?" julkaisi alun perin JavaWorld.