Soru Java “referansla” mı yoksa “değer-değer” mi?


Ben her zaman Java olduğunu düşündüm geçmesi-referansla.

Ancak, birkaç blog yayını gördüm (örneğin, bu blog) öyle olmadığını iddia ediyor.

Yaptığım ayrımı anladığımı sanmıyorum.

Açıklama nedir?


5495


Menşei


Bu konudaki kafa karışıklığının çoğunun, farklı insanların “referans” terimi ile ilgili farklı tanımları olduğu gerçeğine inanıyorum. Bir C ++ arka planından gelen insanlar, "referans" ın, C ++ 'da ne anlama geldiğini ifade etmesi gerektiğini varsayarsa, bir C arkasından gelen kişilerin "referans" ın kendi dillerinde "işaretçi" ile aynı olması gerektiğini varsayar. Java'nın referans ile geçtiğini söylemek doğru olup olmadığı, "referans" ile kastedilene bağlıdır. - Gravity
Bulunan terminolojiyi tutarlı bir şekilde kullanmaya çalışıyorum. Değerlendirme Stratejisi makale. Makale, terimlerin topluluk tarafından büyük ölçüde farklılık gösterdiğine işaret etse de, şunu belirtmek gerekir. için semantik olduğunu vurgular call-by-value ve call-by-reference çok önemli bir şekilde farklı. (Şahsen kullanmayı tercih ederim call-by-object-sharing bu günlerde call-by-value[-of-the-reference]Bu, semantikleri üst düzeyde açıkladığı ve bir çatışma yaratmadığı için call-by-value, hangi olduğu temel uygulama.)
@Gravity: Yorumunuzu BÜYÜK bir ilan panosuna veya başka bir şeye koyabilir misiniz? Kısaca bütün mesele bu. Ve bu her şeyin semantik olduğunu gösteriyor. Bir referansın temel tanımını kabul etmiyorsak, bu sorunun cevabını kabul etmeyeceğiz :) - MadConan
Karşıtlığın "referans anlambilimine" karşı "referans olarak geçmesi" olduğunu düşünüyorum. Java, referans semantik değeriyle değer taşır. - spraff
@Gravity, siz kesinlikle C ++ 'dan gelen insanların içgüdüsel olarak "referans" terimiyle ilgili farklı bir sezgiye sahip olacakları doğru, ben şahsen bedenin "tarafından" daha gömülü olduğuna inanıyorum. "Pass by", Java'da "Passing a" dan kesinlikle farklı olduğu için kafa karıştırıcıdır. C ++ 'da, ancak ortak olarak değildir. C ++ 'da "referansı geçerek" diyebilirsiniz, ve onun geçeceğini anladı swap(x,y) Ölçek.


Cevaplar:


Java her zaman pass-değeri ile. Ne yazık ki, bir nesnenin yerini "referans" olarak adlandırmaya karar verdiler. Bir nesnenin değerini geçtiğimizde, biz referans ona. Bu yeni başlayanlar için kafa karıştırıcı.

Bu böyle devam ediyor:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    // 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 
}

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
}

Yukarıdaki örnekte aDog.getName() hala dönecek "Max". Değer aDog içinde main işlevde değişmez foo ile Dog  "Fifi" nesne referansı değer olarak geçirilir. Referans ile geçirildiyse, o zaman aDog.getName() içinde main dönecekti "Fifi" çağrıdan sonra foo.

Aynı şekilde:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // true
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // this changes the name of d to be "Fifi"
    d.setName("Fifi");
}

Yukarıdaki örnekte, Fifi çağırdıktan sonra köpeğin adı foo(aDog) çünkü nesnenin adı foo(...). Herhangi bir işlem foo üzerinde gerçekleştirir d tüm pratik amaçlar için, onlar üzerinde gerçekleştirilir aDog kendisi (ne zaman hariç d farklı bir işaret edecek şekilde değiştirildi Dog örneğin d = new Dog("Boxer")).


4741



Sorunu iç detaylarla biraz karıştırmamak mı? 'Referansı geçme' ile 'bir referansın değerini geçme' arasında, 'nesneye içsel işaretçinin değeri' anlamına geldiğinizi varsayarsak, kavramsal bir fark yoktur. - izb
Ama ince bir fark var. İlk örneğe bakın. Tamamen referans ile geçtiyse, aDog.name "Fifi" olacaktır. Değildir - elde ettiğiniz referans, fonksiyondan çıkıldığında üzerine yazılırsa geri yüklenecek bir değer referansıdır. - erlando
@Lorenzo: Hayır, Java'da her şey değerden geçiyor. Primitifler, değer ile geçirilir ve nesne referansları, değere göre geçirilir. Nesnelerin kendileri hiçbir zaman bir yönteme geçmez, ancak nesneler her zaman yığındadır ve yalnızca nesneye yapılan bir referans yönteme aktarılır. - Esko Luontola
Nesneyi geçerken görselleştirmenin iyi bir yolundaki girişimim: Bir balon düşünün. Bir fxn çağırmak, ikinci bir dizgeyi balona bağlamak ve çizgiyi fxn'e göndermek gibidir. parametresi = new Balloon () bu dizeyi kesecek ve yeni bir balon oluşturacaktır (ancak bu, orijinal balon üzerinde bir etkisi yoktur). Parametre.pop () yine de dizgeyi açacaktır, çünkü dizgeyi aynı, orijinal balonu izler. Java, değere göre geçer, ancak iletilen değer derin değil, en yüksek düzeyde, yani bir ilkel veya bir işaretçi. Nesnenin tamamen klonlandığı ve geçtiği derin bir geçiş değeriyle karıştırmayın. - dhackner
Kafa karıştırıcı olan şey, nesne referansları aslında işaretçilerdir. Başlangıçta SUN onlara işaretçiler çağırdı. Sonra pazarlama "işaretçisi" nin kötü bir kelime olduğunu bildirdi. Ama yine de NullPointerException'da "doğru" terminolojiyi görüyorsunuz. - Prof. Falken


Sadece referansladığınızı fark ettim makalem.

Java Spec, Java'daki her şeyin değer kat ettiğini söylüyor. Java'da "referans-referans" diye bir şey yoktur.

Bunu anlamanın anahtarı şunun gibi bir şeydir

Dog myDog;

olduğu değil bir köpek; aslında bir Işaretçi bir köpeğe.

Bunun anlamı, sahip olduğunuz zaman

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

esasen sen geçiyorsun adres oluşturulan Dog nesneye foo yöntem.

(Esasen Java işaretçilerinin doğrudan adres olmadığı, ancak bu şekilde düşünmenin en kolay yolu olduğu için söylüyorum)

Varsayalım Dog Nesne bellek adresinde 42 bulunur. Bu demektir ki, 42 yönteme geçeriz.

Yöntem şöyle tanımlanmışsa

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

neler olduğuna bakalım.

  • parametre someDog 42 değerine ayarlanır
  • "AAA" satırında
    • someDog takip edilir Dog işaret eder Dog adresindeki nesne
    • o Dog (42 numaralı adreste) ismini Max olarak değiştirmesi istenir.
  • "BBB" satırında
    • yeni Dog yaratıldı. Diyelim ki adres 74.
    • parametreyi atarız someDog 74
  • "CCC" satırında
    • someDog takip edilir Dog işaret eder Dog adreste nesne 74)
    • o Dog (Adres 74'teki) ismini Rowlf olarak değiştirmesi istenir.
  • o zaman geri dönüyoruz

Şimdi yöntemin dışında neler olduğunu düşünelim:

myDog değişiklik?

Anahtar var.

Bunu akılda tutarak myDog bir Işaretçive gerçek değil Dog, cevap hayır. myDog hala 42 değerine sahiptir; hala orijinali işaret ediyor Dog(Ancak "AAA" satırından dolayı, şimdi adı "Max" - hala aynı Köpek; myDogdeğeri değişmedi.)

Bu kesinlikle geçerli takip et bir adres ve sonunda ne olduğunu değiştirin; Ancak, bu değişkeni değiştirmez.

Java tam olarak C gibi çalışır. Bir işaretçi atayabilir, işaretçiyi bir yönteme aktarabilir, işaretçiyi yöntemde takip edebilir ve işaret edilen verileri değiştirebilirsiniz. Ancak, işaretçinin işaret ettiği yeri değiştiremezsiniz.

C ++, Ada, Pascal ve referansı destekleyen diğer diller, aslında geçen değişkeni değiştirebilirsiniz.

Java, başvuru kaynağı anlambilimine sahipse foo yukarıda tanımladığımız yöntem nerede değişmiş olurdu myDog atandığında işaret ediyordu someDog hatta BBB.

Referans parametrelerini, iletilen değişken için takma ad olarak düşünün. Bu takma ad verildiğinde, iletilen değişkendir.


2639



İşte bu yüzden "Java'nın işaretçilere sahip olmadığı" genelinden kaçınmak çok yanıltıcıdır. - Beska
Sen yanılıyorsun, imho. "MyDog'un gerçek bir Köpek değil, bir işaretçi olduğunu akılda tutarak, cevap HAYIR. MyDog hala 42. değerine sahip, hala orijinal Dog'a işaret ediyor." myDog'un 42 değeri vardır ancak ad argümanı artık // AAA satırında "Rover" yerine "Max" i içerir. - Özgür
Bunu böyle düşün. Birisi Ann Arbor, MI (memleketim, GO MAVİ!) Adresinde "annArborLocation" adında bir kağıt üzerinde bir adrese sahip. "MyDestination" adlı bir kağıda kopyala. "MyDestination" 'a gidebilir ve bir ağaç dikebilirsiniz. Bu konumdaki şehir hakkında bir şey değiştirmiş olabilirsiniz, ancak her iki kağıda yazılmış LAT / LON değerini değiştirmez. "MyDestination" da LAT / LON değerini değiştirebilirsiniz, ancak "annArborLocation" değişmez. Bu yardımcı olur mu? - Scott Stanchfield
@Scott Stanchfield: Yazınızı bir yıl önce okudum ve bu gerçekten benim için işleri açıklığa kavuşturmaya yardımcı oldu. Teşekkürler! Alçakgönüllü bir ekleme önerisinde bulunabilir miyim: Aslında, "Lise'nin dilindeki değerlendirme stratejisini açıklamak için Barbara Liskov tarafından icat edilen" değerin referans olduğu değerden "bu formu açıklayan belirli bir terimin olduğunu belirtmelisiniz. 1974, makale adresiniz gibi karışıklıklardan kaçınmak için: paylaşarak ara (bazen denir nesne paylaşımına göre ara ya da sadece nesneye göre ara), semantikleri oldukça iyi tanımlayan. - Jörg W Mittag
@Gevorg - C / C ++ dilleri bir "işaretçi" kavramına sahip değil. İşaretçiyi kullanan ancak C / C ++ 'nun izin verdiği işaretçi türlerinin aynı türlerine izin vermeyen başka diller vardır. Java'nın işaretçisi var; Sadece yaramazlıklara karşı korunuyorlar. - Scott Stanchfield


Java her zaman argümanları referans ile DEĞİL değerinden geçirir.


Bunu açıklamak istiyorum örnek:

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");
     }
}

Bunu adım adım açıklayacağım:

  1. Adında bir referans bildirmek f türü Foo ve yeni bir nesneye atamak Foo bir öznitelikle "f".

    Foo f = new Foo("f");
    

    enter image description here

  2. Metot tarafında tip referansı Foo bir isimle a bildirildi ve başlangıçta atandı null.

    public static void changeReference(Foo a)
    

    enter image description here

  3. Yöntemi çağırdıkça changeReference, referans a argüman olarak iletilen nesneye atanacaktır.

    changeReference(f);
    

    enter image description here

  4. Adında bir referans bildirmek b türü Foo ve yeni bir nesneye atamak Foo bir öznitelikle "b".

    Foo b = new Foo("b");
    

    enter image description here

  5. a = b referansı yeniden atamak a DEĞİL f özniteliği olan nesneye "b".

    enter image description here


  6. Aradıkça modifyReference(Foo c) yöntem, referans c öznitelikle nesneye oluşturulur ve atanır "f".

    enter image description here

  7. c.setAttribute("c"); başvurulan nesnenin niteliğini değiştirir c ona işaret eder ve aynı referans nesnesi f ona işaret eder.

    enter image description here

Umarım şimdi argüman olarak nesneleri geçirmenin Java'da nasıl çalıştığını anlarsınız :)


1392



+1 Güzel şeyler. iyi diyagramlar. Burada da güzel ve özlü bir sayfa buldum. adp-gmbh.ch/php/pass_by_reference.html Tamam, PHP'de yazıldığını itiraf ediyorum, fakat önemli olduğunu düşündüğüm farkı anlamanın (ve bu farkı ihtiyaçlarınız için nasıl manipüle edeceğinin) fiyatlandırıcısı. - DaveM
@ Eng.Fouad Güzel bir açıklama ama eğer a aynı nesneye işaret eder f(ve asla nesnenin kendi kopyasını almaz f point to), kullanılarak yapılan nesnede yapılan herhangi bir değişiklik a değiştirmeli f aswell (ikisi de aynı nesne ile çalıştıklarından), bu yüzden bir noktada a kendine ait olmalı kopya nesnenin f noktalar. - Mr D
@MRD, 'a' aynı nesneye işaret ettiğinde, 'a' ile işaret edilir, o zaman bu nesneye 'a' üzerinden yapılan herhangi bir değişiklik de 'f' ile gözlemlenebilir, ancak 'f' DEĞİŞTİRMEZ. 'f' hala aynı nesneye işaret ediyor. Nesneyi tamamen değiştirebilirsiniz, ancak 'f' nin neyi göstereceğini asla değiştiremezsiniz. Bu, bazı nedenlerden ötürü bazı insanların kavrayamayacağı temel meseledir. - Mike Braun
Bu bulduğum en iyi açıklama. Bu arada, temel durum ne olacak? Örneğin, argüman int türünü gerektirir, hala int değişkeninin kopyasını argümana iletir mi? - allenwang
Diyagram çok yardımcı oldu - Ivan Kaloyanov


Bu, Java'nın referansla geçirdiğiniz veya değere göre geçen bir sonraki tartışmanızda yalnızca gülümseyeceğiniz :-) noktasında gerçekten nasıl çalıştığıyla ilgili bazı bilgiler verecektir.

Birinci adım, özellikle de diğer programlama dillerinden geliyorsanız, 'p' ile başlayan kelime, _ _ _ _ _ _ _ "diye aklınızdan silin. Java ve 'p' aynı kitapta, forumda veya hatta txt'de yazılmaz.

İkinci adım, bir Nesneyi bir nesneye geçirdiğinizde, Nesne referansını geçtiğinizi ve Nesnenin kendisini değil olduğunu unutmayın.

  • Öğrenci: Efendim, bu Java'nın referansa bağlı olduğu anlamına mı geliyor?
  • ustaÇekirge, hayır.

Şimdi bir Nesne'nin referansının / değişkeninin ne olduğunu / olduğunu düşünün:

  1. Değişken, JVM'ye belleğe atıfta bulunulan nesneye (Yığın) nasıl ulaşılacağını söyleyen bitleri tutar.
  2. Bir yöntemi argümanlara geçirirken Referans değişkeni aktarmıyorsunuz, ancak referans değişkenindeki bitlerin bir kopyası. Böyle bir şey: 3bad086a. 3bad086a, geçirilen nesneye ulaşmanın bir yolunu temsil eder.
  3. Yani 3bad086a'yı geçiyorsunuz, bu referansın değeri.
  4. Referansın değerini geçmiyorsunuz ve referansın kendisi değil (nesne değil).
  5. Bu değer aslında COPIED ve yönteme verildi.

Aşağıda (lütfen şunu derleyin / çalıştırmayın ...):

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. }

Ne oluyor?

  • Değişken kişi # 1 satırında oluşturulur ve başlangıçta sıfırdır.
  • # 2 numaralı satırda, bellekte saklanan yeni bir Kişi Nesnesi ve değişken kişi Kişi nesnesine referans verilir. Yani adresi. 3bad086a diyelim.
  • Değişken kişi Nesnenin adresini tutmak, # 3 satırındaki işleve iletilir.
  • 4. satırda sessizliğin sesini dinleyebilirsiniz.
  • Yorum # 5 satırında kontrol edin
  • Bir yöntem yerel değişkeni -anotherReferenceToTheSamePersonObject- yaratıldı ve sonra # 6 satırında sihir geliyor:
    • Değişken / referans kişi bit-by-bit kopyalanır ve anotherReferenceToTheSamePersonObject fonksiyonun içinde.
    • Yeni bir Kişi örneği oluşturulmaz.
    • Her ikisi de "kişi" ve "anotherReferenceToTheSamePersonObject"3bad086a'nın aynı değerini tutun.
    • Bunu denemeyin ama kişi == anotherReferenceToTheSamePersonObject doğru olurdu.
    • Her iki değişken de referansın KİMLİK KOPYALARI'na sahiptir ve her ikisi de aynı Kişi Nesnesine, ÖĞE'deki ÖĞE Nesnesine ve KOPYA DEĞİL.

Bir resim bin kelime değerinde bir olup:

Pass by Value

AnotherReferenceToTheSamePersonObject oklarının Object'e yönlendirildiğini ve değişken kişiye doğru olmadığını unutmayın!

Eğer anlamadıysan o zaman bana güven ve bunu söylemenin daha iyi olduğunu hatırla. Java değerden geçiyor. İyi, referans değere geçmek. Oh, daha da iyisi pass-by-copy-of-the-değişken değeri! ;)

Şimdi benden nefret etmekten çekinmeyin ama buna dikkat edin. İlkel veri türlerini geçirme ile Nesneler arasında fark yoktur. yöntem argümanlarından bahsederken.

Her zaman referans değerinin bitlerinin bir kopyasını geçirin!

  • İlkel bir veri türü ise, bu bitler ilkel veri türünün kendisinin değerini içerecektir.
  • Bir Nesne ise, bitler, JVM'ye Nesne'ye nasıl ulaşılacağını söyleyen adresin değerini içerecektir.

Java, bir yöntem içinde, başvurulan Nesneyi istediğiniz kadar değiştirebildiğinizden, ancak ne kadar zor olursa olsun, referansı devam ettirecek olan değişkeni değiştiremezsiniz (p_ _ _ _ değil). _ _ _ _) ne olursa olsun aynı Nesne!


Yukarıdaki changeName işlevi, geçirilen referansın asıl içeriğini (bit değerlerini) hiçbir zaman değiştiremez. Başka bir deyişle, changeName, Kişi kişisinin başka bir Nesne başvurmasını sağlayamaz.


Tabii ki kısa kesebilirsin ve şunu söyle Java, değer-değer!


651



İşaretçiler mi demek istiyorsun? public void foo(Car car){ ... }, car yereldir foo ve nesnenin yığın konumunu içerir? Yani değiştirirsem cartarafından değer car = new Car(), yığında farklı Nesne işaret edecek? ve eğer değiştirirsem carmülk valu tarafından car.Color = "Red", Nesne tarafından işaret edilen yığın car değiştirilecek. Ayrıca, C # ile aynı mı? Lütfen cevap verin! Teşekkürler! - dpp
@domanokz Beni öldürüyorsun, lütfen bu kelimeyi bir daha söyleme! ;) Bu soruyu 'referans' demeden de cevaplayabileceğimi unutmayın. Bu bir terminoloji meselesi ve 'p daha da kötüleştiriyor. Ben ve Scot'un maalesef farklı görüşleri var. Java'da nasıl çalıştığını düşünüyorum, şimdi by-value, by-object-by-copy-of-the-value-value-geçişi diyebilirsin ya da başka bir şey bulmakta özgürsün! Nasıl çalıştığını ve nesne türünde bir değişkeni olduğu sürece gerçekten umurumda değil: Sadece bir PO Box adresi! ;) - Gevorg
Sadece sana benziyor referans geçti? Java'nın hala referanslı bir çeviri dili olduğu gerçeğini savunacağım. Kopyalanan bir referans olması, terminolojiyi değiştirmez. Her iki REFERANSLAR hala aynı nesneye işaret ediyor. Bu bir puristin argümanı ... - John Strickler
Java akılda işaretçilerle tasarlanmış sanırım. Aksi halde, neden NullPointerException var? Yine de, bu harika açıklama için, işaretçiler almak sadece karmaşık hale getirecek - brain storm
Yani # 9 teorik satırına gir System.out.println(person.getName()); ne gösterecek? "Tom" ya da "Jerry"? Bu karışıklığı engellememe yardımcı olacak son şey bu. - TheBrenny


Java her zaman istisna olmaksızın, değere geçer hiç.

Öyleyse herkes bununla karıştırılabilir ve Java'nın referans olarak geçtiğine ya da referans olarak geçmesi gereken bir Java örneğine sahip olduklarına inanabilir mi? Önemli nokta Java asla değerlere doğrudan erişim sağlar nesneler kendilerini, içinde herhangi koşullar. Nesnelere tek erişim bir referans bu nesneye Çünkü Java nesneleri her zaman Doğrudan referans yerine, bir referans yoluyla erişilen alanlar ve değişkenler hakkında konuşmak yaygındır. ve yöntem argümanları olarak nesneleripedantically zaman sadece nesnelere başvurular. Karışıklık, isimlendirmede bu (kesin olarak yanlış, yanlış) değişimden kaynaklanır.

Yani, bir yöntem çağrıldığında

  • İlkel argümanlar için (int, longvb), değere göre geçiş gerçek değer ilkel (örneğin, 3).
  • Nesneler için değer, değerin değeridir. nesneye referans.

Eğer varsa doSomething(foo) ve public void doSomething(Foo foo) { .. } iki Foos kopyalandı Referanslar Bu aynı nesnelere işaret eder.

Doğal olarak, değere geçmek, bir nesneye yapılan bir referans, bir nesneyi referans olarak almaktan çok benzer (ve pratikte ayırt edilemez) gibi görünür.


561



İlkellerin değerleri değişmez olduğundan (String gibi), iki durum arasındaki fark gerçekten alakalı değildir. - Paŭlo Ebermann
Kesinlikle. Gözlemlenebilir JVM davranışıyla söyleyebildiğiniz her şey için, ilkel maddeler referans yoluyla geçirilebilir ve yığın üzerinde yaşayabilir. Yapmıyorlar, ama aslında hiçbir şekilde gözlemlenemez. - Gravity
İlkeller değişmez mi? Java 7'de yeni mi? - Carlos Heuberger
@CarlosHeuberger, "ilkeller değişmez mi?" Mesele şu ki taklitBu 'ilkeller' aslında (değişebilir) Referanslar değişmez nesneler. - Aaron McDaid
İşaretçiler imkansızdır, genel olarak ilkel maddeler değişebilirdir. Dize de bir ilkel değil, bir nesnedir. Ayrıca, String'in temel yapısı değişebilir bir dizidir. Bununla ilgili tek değişmez şey, dizilerin doğal doğası olan uzunluktur. - kingfrito_5005


Java referanslara değer kazandırır.

Böylece, geçilen referansı değiştiremezsiniz.


279



Ama tekrarlanmaya devam eden şey “argümanlarda geçen nesnelerin değerini değiştiremezsiniz” açıkça yanlıştır. Onları farklı bir nesneye yönlendiremeyebilirsiniz, ancak içeriklerini yöntemlerini kullanarak değiştirebilirsin. IMO bu, referansların tüm faydalarını yitirdiğiniz ve ek garantiler almadığınız anlamına gelir. - Timmmm
Ben asla "argümanlarda geçen nesnelerin değerini değiştiremezsin" demedim. Java dili hakkında gerçek bir ifade olan "Yöntem argümanı olarak geçirilen nesne referansının değerini değiştiremezsiniz" diyeceğim. Açıkçası, nesnenin durumunu değiştiremezsiniz (değişmez olduğu sürece). - ScArcher2
Nesneleri aslında java'ya aktaramayacağınızı unutmayın; Nesneler yığında kalır. İşaretçiler nesnelere geçirilebilir (aranan yöntem için yığın çerçevesine kopyalanır). Bu yüzden, geçiş değerini (işaretçi) hiçbir zaman değiştirmezsiniz, ancak onu takip etmekte ve o sırada işaret ettiği şeyi değiştirmekte özgürsünüz. Bu değer-değer. - Scott Stanchfield
Sadece sana benziyor referans geçti? Java'nın hala referanslı bir çeviri dili olduğu gerçeğini savunacağım. Kopyalanan bir referans olması, terminolojiyi değiştirmez. Her iki REFERANSLAR hala aynı nesneye işaret ediyor. Bu bir puristin argümanı ... - John Strickler
Java bir nesneyi iletmez, işaretçinin değerini nesneye geçirir. Bu, orijinal nesnenin yeni bellekte yeni bir değişkene yeni bir işaretçi oluşturur. Bir yöntemde bu işaretçi değişkeninin değerini (işaret ettiği adres) değiştirirseniz, yöntem çağrısında kullanılan orijinal işaretçi değiştirilmeden kalır. Eğer parametreyi referans olarak çağırıyorsanız, o zaman kopya Özgün referansın, orijinal referansın kendisi değil, nesneye şimdi iki tane referans olduğu anlamına gelir, bu değer, değer-değerdir - theferrit32


"Pass-by-reference-pass-by-value" hakkında tartışmak gibi hissetmiyorum.

"Java her ne olursa olsun (referans / değer)" diyorsa, her iki durumda da tam bir cevap vermeyeceksiniz. Burada, bellekte neler olup bittiğini anlamaya yardımcı olacak bazı ek bilgiler var.

Java uygulamasına geçmeden önce yığın / yığın halinde kilitlenme kursu: Değerler, bir kafeteryada bir tabak yığını gibi güzel bir düzen içinde yığının üstüne çıkıyor. Yığındaki bellek (dinamik bellek olarak da bilinir) gelişigüzel ve düzensizdir. JVM, mümkün olan her yerde boşluk bulur ve onu kullanan değişkenlere artık ihtiyaç duymadığından onu serbest bırakır.

Tamam. İlk kapalı, yerel ilkeller yığının üstüne gider. Yani bu kod:

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

sonuç:

primitives on the stack

Bir nesneyi bildirip başlattığınızda. Asıl nesne yığın üzerinde gider. Yığında ne var? Yığındaki nesnenin adresi. C ++ programcıları buna bir işaretçi diyordu, ancak bazı Java geliştiricileri "işaretçi" kelimesine karşı. Her neyse. Sadece nesnenin adresinin yığınının üzerinde olduğunu bilin.

Öyle:

int problems = 99;
String name = "Jay-Z";

a b*7ch aint one!

Bir dizi bir nesnedir, bu yüzden yığın üzerinde de devam eder. Peki ya dizi içindeki nesneler? Kendi yığın alanlarını alırlar ve her nesnenin adresi dizinin içine girer.

JButton[] marxBros = new JButton[3];
marxBros[0] = new JButton("Groucho");
marxBros[1] = new JButton("Zeppo");
marxBros[2] = new JButton("Harpo");

marx brothers

Öyleyse, bir yöntem çağırdığında ne geçiyor? Bir nesneyi iletirseniz, aslında girdiğiniz şey nesnenin adresidir. Bazıları adresin "değerini" söyler, bazıları ise sadece nesnenin bir referansı olduğunu söyler. Bu, "referans" ve "değer" taraftarları arasındaki kutsal savaşın doğuşudur. Buna ne denir, neyin geçtiğini anlamak, nesnenin adresidir.

private static void shout(String name){
    System.out.println("There goes " + name + "!");
}

public static void main(String[] args){
    String hisName = "John J. Jingleheimerschmitz";
    String myName = hisName;
    shout(myName);
}

Bir String yaratılır ve bu alan yığın içinde ayrılır ve dizeye verilen adres yığın üzerinde saklanır ve tanımlayıcı verilir. hisNameikinci dizenin adresi ilk ile aynı olduğundan, yeni bir String oluşturulmadığından ve yeni yığın alanı tahsis edilmediğinden, yığında yeni bir tanımlayıcı oluşturulur. Sonra aradık shout(): Yeni bir yığın çerçevesi oluşturulur ve yeni bir tanımlayıcı, name önceden varolan String'in adresi oluşturulur ve atanır.

la da di da da da da

Yani, değer, referans? "Patates" diyorsun.


198



Bununla birlikte, bir fonksiyonun bir referansı olan bir değişkeni değiştirdiği bir fonksiyonun daha karmaşık bir örneğini izlemiş olmalısınız. - Brian Peterson
İnsanlar yığınla yığının "gerçek meselesinde dans etmiyor", çünkü bu değil asıl konu. En iyi ihtimalle bir uygulama detayı ve en kötüsüyle yanlıştır. (Nesnelerin yığında yaşamak için mümkün, google "kaçış analizi". Ve çok sayıda nesne, muhtemelen ilkelleri içerir. yapamaz yığında yaşamak.) asıl mesele kesinlikle Referans türleri ve değer türleri arasındaki fark - özellikle, referans tipi değişkenin değeri, başvurulan nesne değil, bir referanstır. - cHao
Bu, bir nesnenin hafızada nerede yaşadığını göstermek için gerçekte Java'nın bir daha asla gerekli olmadığı bir “uygulama detayı” dır. önlemek Bu bilgiyi sızdırıyor. Nesneyi yığına koyabilir ve asla bilmezsiniz. Eğer ilgilenirsen, yanlış olana odaklanırsın - ve bu durumda, gerçek meseleyi görmezden gelir. - cHao
Ve her iki şekilde de "ilkel yığınlara devam ediyor" yanlış. İlkel yerel değişkenler yığının üstüne git. (Tabii ki, uzaklaşmamışlarsa tabii ki.) Ama sonra, yerel referans değişkenleri de. Nesne içinde tanımlanan ilkel üyeler, nesnenin yaşadığı her yerde yaşarlar. - cHao
Burada yorumlarla katılıyorum. Yığın / yığın bir yan konu ve ilgili değil. Bazı değişkenler yığında bulunabilir, bazıları statik bellekte (statik değişkenler) ve yığın üzerinde bol miktarda (tüm nesne üyesi değişkenleri) olabilir. Bu değişkenlerin hiç biri referans olarak iletilebilir: aranan bir yöntemden, argüman olarak iletilen bir değişkenin değerini değiştirmek mümkün değildir. Bu nedenle, Java'da herhangi bir başvuru kaynağı yoktur. - fishinear