Ar „Java“ yra „po-nuoroda“ arba „pagal vertę“?

Visada maniau, kad java yra perduodanti nuoroda .

Tačiau mačiau keletą dienoraščio įrašų (pvz., Šio dienoraščio ), teigdamas, kad taip nėra.

Nemanau, kad suprantu skirtumą, kurį jie daro.

Kas yra paaiškinimas?

5703
02 сент. user4315 yra nustatytas 02 sept. 2008-09-02 23:14 '08 at 23:14 pm 2008-09-02 23:14
@ 92 atsakymai

„Java“ visada perduodama pagal vertę . Deja, kai perduodame objekto vertę, mes perduodame nuorodą. Tai painioti pradedantiesiems.

Tai atrodo taip:

 public static void main(String[] args) { Dog aDog = new Dog("Max"); Dog oldDog = aDog; // we pass the object to foo foo(aDog); // aDog variable is still pointing to the "Max" dog when foo(...) returns aDog.getName().equals("Max"); // true aDog.getName().equals("Fifi"); // false aDog == oldDog; // true } public static void foo(Dog d) { d.getName().equals("Max"); // true // change d inside of foo() to point to a new Dog instance "Fifi" d = new Dog("Fifi"); d.getName().equals("Fifi"); // true } 

Pirmiau pateiktame pavyzdyje aDog.getName() vis tiek grąžins "Max" . Pagrindinė „ aDog reikšmė foo funkcijoje nesikeičia su "Fifi" Dog , nes nuoroda į objektą yra perduodama pagal vertę. Jei jis buvo priimtas pagal nuorodą, tada aDog.getName()main sugrįš "Fifi" po to, kai paskambinsite foo .

Panašiai:

 public static void main(String[] args) { Dog aDog = new Dog("Max"); Dog oldDog = aDog; foo(aDog); // when foo(...) returns, the name of the dog has been changed to "Fifi" aDog.getName().equals("Fifi"); // true // but it is still the same dog: aDog == oldDog; // true } public static void foo(Dog d) { d.getName().equals("Max"); // true // this changes the name of d to be "Fifi" d.setName("Fifi"); } 

Pirmiau pateiktame pavyzdyje Fifi yra šuns vardas, kai jis vadinamas foo(aDog) nes objekto pavadinimas buvo nustatytas foo(...) . Bet kokie veiksmai, kuriuos atlieka d yra tokie, kad visais praktiniais tikslais jie atliekami su aDog , bet neįmanoma pakeisti aDog kintamojo vertės.

5068
02 сент. atsakymas duotas erlando 02 Sep 2008-09-02 23:25 '08, 23:25, 2008-09-02 23:25

Aš tik pastebėjau, kad paminėjote mano straipsnį .

„Java Spec“ sako, kad viskas „Java“ yra perduodama pagal vertę. Nėra tokio dalyko, kaip Java.

Svarbiausia suprasti tai, kad kažkas panašaus

 Dog myDog; 

nėra šuo; tai iš tikrųjų yra rodyklė šuniui.

Ką tai reiškia, kai turite

 Dog myDog = new Dog("Rover"); foo(myDog); 

jūs iš esmės perduodate sukurto Dog objekto adresą į foo metodą.

(Iš tiesų sakau, nes „Java“ rodyklės nėra tiesioginiai adresai, bet paprasčiausias būdas tai mąstyti)

Tarkime, kad Dog objektas yra atminties adresu 42. Tai reiškia, kad mes išlaikome 42 metodą.

jei metodas buvo apibrėžtas kaip

 public void foo(Dog someDog) { someDog.setName("Max"); // AAA someDog = new Dog("Fifi"); // BBB someDog.setName("Rowlf"); // CCC } 
border=0

pamatyti, kas vyksta.

  • parametras someDog nustatytas kaip 42
  • eilutėje „AAA“
    • someDog taikomas Dog , kuris nurodo ( Dog objektas adresu 42)
    • į Dog (42 adresas) paprašė pakeisti savo vardą į Max
  • eilutėje „BBB“
    • Sukuriamas naujas Dog . Tarkime, tai yra 74
    • parametrą someDog į 74
  • „CCC“ eilutėje
    • someDog seka Dog , kuris rodo ( Dog objektas 74)
    • į Dog (74 adresas), paprašė pakeisti savo vardą į Rowlf
  • tada sugrįšime

Dabar pagalvokite, kas vyksta už metodo ribų:

Ar myDog pasikeitė?

Čia yra raktas.

Turint omenyje, kad myDog yra rodyklė, o ne tikrasis Dog , atsakymas yra NE. myDog vis dar yra 42; jis vis tiek nurodo pradinį Dog (tačiau atkreipkite dėmesį, kad dėl eilutės „AAA“ jo vardas dabar yra „Max“ - tas pats šuo, „ myDog nepasikeitė.)

Tiksliai sekti adresą ir pakeisti, kas yra jo pabaigoje; tačiau nekeičia kintamojo.

„Java“ veikia taip pat, kaip ir C. Galite priskirti žymeklį, perkelti žymeklį prie metodo, sekti rodyklę metode ir pakeisti nurodytus duomenis. Tačiau negalite keisti, kur šis žymeklis nurodo.

C ++, Ada, Pascal ir kitomis kalbomis, kurios palaiko nuorodą, galite iš tikrųjų keisti perduotą rodiklį.

Jei „Java“ turi myDog nuorodos semantiką, pirmiau apibrėžtas „ foo metodas pasikeistų, kai „ myDog rodoma, kai someDog linijoje priskyrė tam someDog “.

Pagalvokite apie pamatinius parametrus kaip perduodamo kintamojo slapyvardžius. Kai priskiriamas šis slapyvardis, taip pat kintamasis, kuris buvo perduotas.

2768
16 сент. Scott Stanchfield atsakymas, pateiktas rugsėjo 16 d 2008-09-16 17:37 '08 at 17:37 pm 2008-09-16 17:37

Java visada perduoda argumentus pagal vertę, o ne pagal nuorodą.


Leiskite paaiškinti pavyzdžiu :

 public class Main{ public static void main(String[] args){ Foo f = new Foo("f"); changeReference(f); // It won't change the reference! modifyReference(f); // It will modify the object that the reference variable "f" refers to! } public static void changeReference(Foo a){ Foo b = new Foo("b"); a = b; } public static void modifyReference(Foo c){ c.setAttribute("c"); } } 

Aš tai paaiškinsiu:

  1. Nuorodos su Foo tipo f pavadinimu deklaravimas ir jam priskiriamas naujas Foo tipo objektas su atributu "f" .

     Foo f = new Foo("f"); 

    2019

1472
14 сент. atsakymas pateikiamas Eng.Fouad 14 sep . 2012-09-14 21:22 '12 at 9:22 pm 2012-09-14 21:22

Tai suteiks jums idėją, kaip „Java“ iš tikrųjų veikia tokiu mastu, kad kitoje diskusijoje apie „Java“ persiuntimą pagal nuorodą arba pagal vertę, jūs tiesiog šypsotės: -)

Pirmas žingsnis, pašalinkite iš savo proto šį žodį, kuris prasideda „p“ „_ _ _ _ _ _ _“, ypač jei esate iš kitų programavimo kalbų. „Java“ ir „p“ negali būti parašytos toje pačioje knygoje, forume ar net txt.

2 žingsnis: nepamirškite, kad perduodant objektą prie metodo, jūs perduodate objekto nuorodą, o ne patį objektą.

  • Studentas: Mokytojas, ar tai reiškia, kad „Java“ praeina pagal nuorodą?
  • Meistras: žiogas, ne.

Dabar pagalvokite apie tai, kuri nuoroda / Objekto kintamasis turi:

  • Kintamasis apima bitus, kurie nurodo JVM, kaip eiti į nurodytą objektą atmintyje (krūvose).
  • Kai perduodate metodui argumentus, NESKYRUS referencinio kintamojo, bet atskaitos kintamojo bitų kopija . Kažkas panašaus: 3bad086a. 3bad086a yra būdas pasiekti perduotą objektą.
  • Taigi, jūs tiesiog pereinate 3bad086a, tai yra nuorodos vertė.
  • Jūs perduodate nuorodos vertę, o ne nuorodą (o ne objektą).
  • Ši vertė iš tikrųjų yra COPED ir suteikta metodui .

Toliau (nebandykite surinkti / vykdyti ...):

 1. Person person; 2. person = new Person("Tom"); 3. changeName(person); 4. 5. //I didn't use Person person below as an argument to be nice 6. static void changeName(Person anotherReferenceToTheSamePersonObject) { 7. anotherReferenceToTheSamePersonObject.setName("Jerry"); 8. } 

Kas vyksta

  • Kintamojo vartotojas sukuriamas eilutėje # 1, o pradžioje yra nulinis.
  • Naujas Asmuo objektas sukurtas eilutėje # 2, saugomas atmintyje, ir kintamajam priskiriama nuoroda į Asmenį, kuris prieštarauja kintamajam. Tai yra jo adresas. Pasakykite 3bad086a.
  • Kintamojo, kuriame yra objekto adresas, veidas perduodamas funkcijai # 3 eilutėje.
  • # 4 eilutėje galite klausytis tylos garso.
  • Pažymėkite komentarą # 5 eilutėje
  • Sukurtas vietinio kintamojo metodas -anotherReferenceToTameSamePersonObject- ir tada magija pasirodo eilutėje 6:
    • Kintamojo / nuorodos vartotojas kopijuojamas bitais ir perduodamas kitam „ReferenceToTameSamePersonObject“ funkcijai.
    • Nėra naujų Asmens atvejų.
    • Tiek „asmuo“, tiek „kitasReferenceToTameSamePersonObject“ išsaugo tą pačią vertę 3bad086a.
    • Nebandykite to padaryti, bet žmogus == anotherReferenceToTamePersonObject bus teisingas.
    • Abu kintamieji turi nuorodos IDENTIFIKAVIMO KOPIJUS, ir abu yra susiję su tuo pačiu asmeniu objektu, pačiu objektu ant krūvos ir NE KOPIJU.

Vaizdas yra tūkstantis žodžių:

2019

680
12 авг. Gevorgui pateiktas atsakymas rugpjūčio 12 d 2011-08-12 04:22 '11 at 4:22 2011-08-12 04:22

„Java“ visada pasiekia vertę, jokių išimčių.

Taigi, kaip visa tai gali būti supainioti, ir jie mano, kad „Java“ seka nuorodą, arba mano, kad jie turi „Java“ pavyzdį, veikiantį kaip nuorodą? Svarbiausias dalykas yra tai, kad „Java“ jokiomis aplinkybėmis niekada nesuteikia tiesioginės prieigos prie pačių objektų vertybių. Vienintelė prieiga prie objektų yra nuoroda į šį objektą. Kadangi „Java“ objektai visada pasiekiami per nuorodą, o ne tiesiogiai, paprastai sakoma, kad metodo laukai, kintamieji ir argumentai yra objektai, kai pedantiškai jie yra tik nuorodos į objektus. Sumišimas kyla dėl šio (griežtai kalbant, neteisingo) nomenklatūros pakeitimo.

Taigi, kai skambinate metodu

  • Primityviems argumentams ( int , long ir pan.) Praleidžiant pagal vertę yra tikroji primityvioji vertė (pvz., 3).
  • Objektams objektų nuorodos reikšmė perduodama pagal vertę.

Taigi, jei turite doSomething(foo) ir public void doSomething(Foo foo) { .. } , du „Foos“ nukopijavo nuorodas į tuos pačius objektus.

Natūralu, kad, perduodant objekto nuorodą, praktiškai labai panašus (ir neatskiriamas) nuo objekto perdavimo.

599
02 сент. Atsakymas pateikiamas SCdF 02 Sep. 2008-09-02 23:19 '08 at 11:19 pm 2008-09-02 23:19

„Java“ perduoda nuorodas pagal vertę.

Taigi negalite keisti perduodamos nuorodos.

290
02 сент. Atsakymas pateikiamas ScArcher2 02 Sep. 2008-09-02 23:20 '08, 23:20, 2008-09-02 23:20

Man atrodo, kad argumentas apie „praeities ir pasyvumo vertę“ nėra labai naudingas.

Jei sakote: „„ Java “yra perduodama bet kokiu būdu (nuoroda / vertė), bet kuriuo atveju, jūs nepateikiate išsamaus atsakymo. Štai keletas papildomos informacijos, kuri, tikiuosi, padės jums suprasti, kas vyksta atmintyje.

„Crash“ kursas kamino / krūvos metu prieš pradedant „Java“ diegimą: vertybės pakyla į krūvą ir sukrauti taip gerai, kaip valgomojo lėkštės krūva. Heap atmintis (taip pat žinoma kaip dinamiška atmintis) yra nepatogus ir nesuderinamas. JVM tiesiog suranda vietą, kur ji gali, ir ją atleidžia, nes kintamieji, kurie ją naudoja, nebėra reikalingi.

Geras Pirma, vietiniai primityvai eina į steką. Taigi šis kodas:

 int x = 3; float y = 101.1f; boolean amIAwesome = true; 

sukelia:

2019

210
11 сент. atsakymas suteiktas cutmancometh 11 sept. 2013-09-11 14:34 '13, 14:34, 2013-09-11 14:34

Jei norite parodyti kontrastą, palyginkite šiuos „ C ++“ ir „ Java“ fragmentus:

C ++: Pastaba. Blogas kodas - atminties nutekėjimas! Tačiau tai rodo tašką.

 void cppMethod(int val, int  Dog obj, Dog  Dog *objPtr, Dog * { val = 7; // Modifies the copy ref = 7; // Modifies the original variable obj.SetName("obj"); // Modifies the copy of Dog passed objRef.SetName("objRef"); // Modifies the original Dog passed objPtr->SetName("objPtr"); // Modifies the original Dog pointed to // by the copy of the pointer passed. objPtr = new Dog("newObjPtr"); // Modifies the copy of the pointer, // leaving the original object alone. objPtrRef->SetName("objRefPtr"); // Modifies the original Dog pointed to // by the original pointer passed. objPtrRef = new Dog("newObjPtrRef"); // Modifies the original pointer passed } int main() { int a = 0; int b = 0; Dog d0 = Dog("d0"); Dog d1 = Dog("d1"); Dog *d2 = new Dog("d2"); Dog *d3 = new Dog("d3"); cppMethod(a, b, d0, d1, d2, d3); // a is still set to 0 // b is now set to 7 // d0 still have name "d0" // d1 now has name "objRef" // d2 now has name "objPtr" // d3 now has name "newObjPtrRef" } 

„Java“

 public static void javaMethod(int val, Dog objPtr) { val = 7; // Modifies the copy objPtr.SetName("objPtr") // Modifies the original Dog pointed to // by the copy of the pointer passed. objPtr = new Dog("newObjPtr"); // Modifies the copy of the pointer, // leaving the original object alone. } public static void main() { int a = 0; Dog d0 = new Dog("d0"); javaMethod(a, d0); // a is still set to 0 // d0 now has name "objPtr" } 

„Java“ turi tik dviejų tipų perkėlimus: pagal vertę, skirtą įmontuotiems tipams, ir rodyklės reikšmę objektų tipams.

172
17 сент. atsakymą pateikė „ Eclipse 17 sep“. 2008-09-17 20:38 '08 8:38 pm 2008-09-17 20:38

„Java“ perduoda objektų nuorodas pagal vertę.

152
02 сент. Atsakymą pateikė John Channing 02 Sep. 2008-09-02 23:23 '08, 23:23, 2008-09-02 23:23

Iš esmės, perkeliant objekto parametrus, argumentas, pavyzdžiui, neturi įtakos.

 private void foo(Object bar) { bar = null; } public static void main(String[] args) { String baz = "Hah!"; foo(baz); System.out.println(baz); } 

bus spausdinti "Hah!" vietoj null . Priežastis, kodėl tai veikia, yra ta, kad bar yra bazinės vertės kopija, kuri yra tiesiog nuoroda į "Hah!" Jei tai būtų tikra nuoroda, tada foo iš naujo apibrėžtų baz į null .

145
02 сент. Hank Gay paskelbė 02 Sep 2008-09-02 23:21 '08, 11:21 val. 2008-09-02 23:21

Negaliu patikėti, kad niekas paminėjo Barbarą Liškovą. Kai ji 1974 m. Sukūrė CLU, ji susidūrė su ta pačia terminologijos problema, ir ji sukūrė terminą „iššūkis“ dalydamiesi (taip pat vadinamu skambučiu, dalydamasis objektais ir skambindama objektu) šiam konkrečiam atvejui „skambinti pagal vertę, kur nuoroda ".

143
08 сент. Atsakymą pateikė Jörg W Mittag 08 Sep. 2010-09-08 01:07 '10, 1:07, 2010-09-08 01:07

Esmė yra ta, kad frazės „sekti nuorodą“ žodinė nuoroda reiškia kažką, kas visiškai skiriasi nuo įprastos „Java“ nuorodos reikšmės.

Paprastai „Java“ nuoroda reiškia objekto nuorodą. Tačiau techniniai terminai, perduodami pagal programavimo kalbos teoriją, yra nuorodos į atminties elementą, kuriame yra kintamasis, kuris yra visiškai kitoks.

103
12 янв. atsakymą pateikė JacquesB 12 sausis 2009-01-12 23:50 '09, 11:50 pm 2009-01-12 23:50

„Java“ sistemoje viskas yra nuoroda, taigi, kai turite kažką panašaus: Point pnt1 = new Point(0,0); „Java“ atlieka šiuos veiksmus:

  • Sukuria naują taško objektą.
  • Sukuria naują nuorodą į tašką ir inicijuoja šią nuorodą į anksčiau sukurto taško objekto tašką (žr.).
  • Iš čia, per „Point“ objekto gyvenimą, šį objektą galėsite pasiekti naudodami „pnt1“ žinyną. Todėl galime pasakyti, kad „Java“ manipuliuoja objektu per savo nuorodą.

2019

76
21 нояб. atsakymas pateikiamas Srle, lapkričio 21 d. 2013-11-21 19:04 '13, 19:04, 2013-11-21 19:04

Java visada eina pagal vertę, o ne pagal nuorodą.

Visų pirma, mes turime suprasti, kas praeina pagal vertę ir eina pagal nuorodą.

Reikšmės perdavimas reiškia, kad kopijuojate tikrosios perduodamo parametro vertės atmintyje. Tai faktinio parametro turinio kopija .

Perdavimas pagal nuorodą (taip pat vadinamas praeiti adresu) reiškia, kad išsaugomas faktinio parametro adreso kopija .

Kartais „Java“ gali duoti iliuziją, kad bus perduota nuoroda. Žiūrėkite, kaip tai veikia toliau pateiktu pavyzdžiu:

 public class PassByValue { public static void main(String[] args) { Test t = new Test(); t.name = "initialvalue"; new PassByValue().changeValue(t); System.out.println(t.name); } public void changeValue(Test f) { f.name = "changevalue"; } } class Test { String name; } 

Šios programos rezultatas yra:

 changevalue 

Suprasti žingsnis po žingsnio:

 Test t = new Test(); 

Kaip mes visi žinome, jis sukurs objektą krūvoje ir grąžins pradinę vertę atgal į t. Например, предположим, что значение t равно 0x100234 (мы не знаем фактического внутреннего значения JVM, это просто пример).

 new PassByValue().changeValue(t); 

При прохождении ссылочного т к функции не будет непосредственно передавать фактическое значение задания теста объекта, но это создаст копию т, а затем передать его в функцию. Поскольку он передается по значению , он передает копию переменной, а не фактическую ссылку на нее. Поскольку мы сказали, что значение t 0x100234 , оба t и f будут иметь одинаковое значение и, следовательно, они будут указывать на один и тот же объект.

Если вы измените что-либо в функции с помощью ссылки f, оно изменит существующее содержимое объекта. Вот почему мы получили значение changevalue , которое обновляется в функции.