Neden Java'daki bir yöntem parametresinde “final” anahtar sözcüğünü kullanmalıyım?


381

Yöntem parametrelerinde kullanıldığında finalanahtar kelimenin gerçekten kullanışlı olduğunu anlayamıyorum .

Anonim sınıfların kullanımını, okunabilirliği ve niyet beyanını hariç tutarsak, bu benim için neredeyse değersiz görünüyor.

Bazı verilerin sabit kalmasını sağlamak, göründüğü kadar güçlü değildir.

  • Parametre bir ilkel ise, parametre bir değer olarak yönteme geçirildiği ve değiştirilmesinin kapsam dışında bir etkisi olmayacağından, hiçbir etkisi olmayacaktır.

  • Bir parametreyi başvuru ile geçiriyorsak, başvurunun kendisi yerel bir değişkendir ve başvuru yöntemin içinden değiştirilirse, yöntem kapsamının dışından herhangi bir etkisi olmaz.

Aşağıdaki basit test örneğini düşünün. Bu test, yöntem kendisine verilen referansın değerini değiştirmesine rağmen, hiçbir etkisi yoktur.

public void testNullify() {
    Collection<Integer> c  = new ArrayList<Integer>();      
    nullify(c);
    assertNotNull(c);       
    final Collection<Integer> c1 = c;
    assertTrue(c1.equals(c));
    change(c);
    assertTrue(c1.equals(c));
}

private void change(Collection<Integer> c) {
    c = new ArrayList<Integer>();
}

public void nullify(Collection<?> t) {
    t = null;
}

101
Terminolojiyle ilgili hızlı bir nokta - Java'nın hiç doğrudan referansı yoktur. Aynı şey olmayan değere göre geçiş referansı vardır . Referans semantik ile gerçek geçiş ile kodunuzun sonuçları farklı olacaktır.
Jon Skeet

6
Referansla geçiş ile değere göre geçiş referansı arasındaki fark nedir?
NobleUplift

Bu farkı bir C bağlamında tanımlamak daha kolaydır (en azından benim için). Bir işaretçiyi: <code> int foo (int bar) </code> gibi bir yönteme geçirirsem , bu işaretçi değere göre geçirilir. Bu kopyalanır anlamına gelir, eğer bu yöntem içinde <code> free (bar) gibi bir şey yaparsam; bar = malloc (...); </code> o zaman gerçekten çok kötü bir şey yaptım. Ücretsiz görüşme aslında işaret edilen bellek yığınını serbest bırakacaktır (böylece hangi işaretçi olursa olsun şimdi sarkıyor). Ancak, <code> int foo (int & bar) </bar>, kodun geçerli olduğu ve iletilen işaretçinin değerinin değiştirileceği anlamına gelir.
jerslan

1
Birincisi int foo(int* bar)ve sonuncusu olması gerekiyordu int foo(int* &bar). İkincisi referans olarak bir işaretçi geçirir, birincisi değere göre bir referans geçirir.
jerslan

2
@ Martin, bence bu iyi bir soru ; soru için başlık ve neden için bir açıklama olarak yayın içeriğini görmek için soru sorulur. Belki buradaki kuralları yanlış anlıyorum, ama bu tam olarak "yöntemlerde son parametrelerin kullanımı" ararken istediğim sorudur .
Victor Zamanian

Yanıtlar:


239

Bir Değişkenin Yeniden Atanmasını Durdurma

Bu cevaplar entelektüel olarak ilginç olsa da, kısa basit cevabı okumadım:

Derleyicinin bir değişkenin farklı bir nesneye yeniden atanmasını önlemek istediğinizde final anahtar sözcüğünü kullanın .

Değişken statik bir değişken, üye değişken, yerel değişken veya bağımsız değişken / parametre değişkeni olsun, efekt tamamen aynıdır.

Misal

Etkisini eylemde görelim.

İki değişkenin ( arg ve x ) her ikisine de farklı nesneler atanabildiği bu basit yöntemi düşünün .

// Example use of this method: 
//   this.doSomething( "tiger" );
void doSomething( String arg ) {
  String x = arg;   // Both variables now point to the same String object.
  x = "elephant";   // This variable now points to a different String object.
  arg = "giraffe";  // Ditto. Now neither variable points to the original passed String.
}

Yerel değişkeni son olarak işaretleyin . Bu derleyici hatasıyla sonuçlanır.

void doSomething( String arg ) {
  final String x = arg;  // Mark variable as 'final'.
  x = "elephant";  // Compiler error: The final local variable x cannot be assigned. 
  arg = "giraffe";  
}

Bunun yerine, parametre değişkenini final olarak işaretleyelim . Bu da derleyici hatasıyla sonuçlanır.

void doSomething( final String arg ) {  // Mark argument as 'final'.
  String x = arg;   
  x = "elephant"; 
  arg = "giraffe";  // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
}

Hikayeden çıkarılacak ders:

Bir değişkenin her zaman aynı nesneyi gösterdiğinden emin olmak istiyorsanız, son değişkeni işaretleyin .

Asla Bağımsız Değişkenleri Yeniden Atama

İyi programlama pratiği olarak (herhangi bir dilde), çağıran yöntem tarafından iletilen nesneden başka bir nesneye hiçbir zaman parametre / argüman değişkeni atamamalısınız. Yukarıdaki örneklerde, asla satır yazılmamalıdır arg =. İnsanlar hata yaptığı ve programcılar insan olduğu için derleyiciden bize yardım etmesini isteyelim. Her parametre / bağımsız değişken değişkenini 'son' olarak işaretleyin, böylece derleyici bu tür yeniden atamaları bulabilir ve işaretleyebilir.

Geçmişe bakıldığında

Diğer cevaplarda belirtildiği gibi ... Java'nın programcılara bir dizinin sonunu okumak gibi aptalca hatalardan kaçınmasına yardımcı olan özgün tasarım hedefi göz önüne alındığında, Java tüm parametre / argüman değişkenlerini otomatik olarak 'nihai' olarak uygulamak için tasarlanmış olmalıdır. Başka bir deyişle, Bağımsız Değişkenler değişken olmamalıdır . Ancak gezinin 20/20 vizyonu var ve Java tasarımcıları o zamanlar ellerini doluydu.

Yani, her zaman finaltüm argümanlara eklensin mi?

finalBildirilen her bir metod parametresine eklememiz gerekir mi?

  • Teorik olarak, evet.
  • Uygulamada, hayır.
    Only finalYalnızca yöntemin kodu uzun veya karmaşıksa, bağımsız değişkenin yerel veya üye bir değişkenle karıştırılabileceği ve muhtemelen yeniden atanabileceği durumlarda ekleyin .

Asla bir argümanı yeniden atama pratiği satın alırsanız, finalher birine bir tane eklemeye meyilli olacaksınız . Ancak bu sıkıcı ve bildirimin okunmasını biraz zorlaştırıyor.

Bağımsız değişken açıkçası bir bağımsız değişken olduğu ve basit bir değişken veya bir üye değişkeni kısa kısa kod için, ben ekleme zahmet etmeyin final. Kod oldukça açıksa, ne şansım ne de başka bir programcı, argüman değişkenini yanlışlıkla bir argümandan başka bir şey olarak yanlış bir şekilde bozan bakım veya yeniden düzenleme yapmazsa, rahatsız etmeyin. Kendi çalışmamda, finalyalnızca bir argümanın yerel veya üye değişkenle karıştırılabileceği daha uzun veya daha fazla ilgili kod ekliyorum .

Bütünlük için bir vaka daha eklendi

public class MyClass {
    private int x;
    //getters and setters
}

void doSomething( final MyClass arg ) {  // Mark argument as 'final'.

   arg =  new MyClass();  // Compiler error: The passed argument variable arg  cannot be re-assigned to another object.

   arg.setX(20); // allowed
  // We can re-assign properties of argument which is marked as final
 }

23
"İyi bir programlama uygulaması olarak (herhangi bir dilde), asla bir parametre / argüman değişkeni atamamalısınız [..]" Üzgünüm, bu konuda sizi gerçekten çağırmak zorundayım. Değişkenleri yeniden atamak, Javascript gibi dillerde standart uygulamadır; burada, geçirilen argümanların miktarı (veya geçirilmiş olsalar bile) yöntem imzası tarafından dikte edilmez. Örneğin, "işlev say (msg)" gibi bir imza verildiğinde, insanlar 'msg' argümanının atandığından emin olurlar: "msg = msg || 'Merhaba Dünya!';". Dünyanın en iyi Javascript programcıları iyi uygulamalarınızı kırıyorlar. Sadece jQuery kaynağını okuyun.
Stijn de Witt

37
@StijndeWitt Örneğiniz, bağımsız değişken değişkenini yeniden atama sorununu gösterir. Karşılığında hiçbir şey kazanmadan bilgi kaybedersiniz : (a) Geçilen orijinal değeri kaybettiniz, (b) Çağıran yöntemin niyetini kaybettiniz (Arayan 'Merhaba Dünya!' Yı geçti mi yoksa varsayılan mı?) Hem a & b hem de test, uzun kod ve değer daha sonra değiştirildiğinde yararlıdır. Ben ifademin yanındayım: arg vars asla yeniden atanmamalıdır. Sizin kodu olmalıdır: message = ( msg || 'Hello World"' ). Hiçbir sebep Orada sadece değil , ayrı bir var kullanmak için. Tek maliyet birkaç bayt bellek.
Basil Bourque

9
@Basil: Daha fazla kod (bayt cinsinden) ve Javascript'te sayılır. Ağır şekilde. Birçok şeyde olduğu gibi, görüşe dayalıdır. Bu programlama uygulamasını tamamen görmezden gelmek ve yine de mükemmel kod yazmak tamamen mümkündür. Bir kişinin programlama pratiği onu herkesin pratiği yapmaz. Her şeyin yanında dur, yine de farklı yazmayı seçiyorum. Bu beni kötü bir programcı mı, yoksa kodum kötü kod mu yapıyor?
Stijn de Witt

14
Kullanılması message = ( msg || 'Hello World"' )beni daha sonra yanlışlıkla kullanarak riskleri msg. Anlaştığım sözleşme "no / null / undefined arg ile davranış geçmekten ayırt edilemez "Hello World"" olduğunda, fonksiyonun erken aşamalarında bunu yerine getirmek iyi bir programlama uygulamasıdır. [Bu, yeniden atama olmadan başlayabilir, if (!msg) return myfunc("Hello World");ancak birden fazla argümana sahip değildir.] İşlevdeki mantığın varsayılanın kullanılıp kullanılmadığına dikkat etmesi gereken nadir durumlarda, özel bir sentinel değeri (tercihen halka açık) tercih ederim .
Beni Cherniavsky-Paskin

6
@ BeniCherniavsky-Paskin tarif ettiğiniz risk sadece messageve arasındaki benzerlikten kaynaklanmaktadır msg. Ancak buna processedMsgek bağlam sağlayan bir şey veya başka bir şey derse - hata şansı çok daha düşüktür. “Nasıl” dediğine değil , söylediklerine odaklanın . ;)
alfasin

230

Bazen değişkenin değişmediği açık (okunabilirlik için) olabilir. Kullanmanın finalbazı olası baş ağrılarını kurtarabileceği basit bir örnek :

public void setTest(String test) {
    test = test;
}

Bir ayarlayıcıdaki 'bu' anahtar kelimeyi unutursanız, ayarlamak istediğiniz değişken ayarlanmaz. Ancak, finalparametrede anahtar kelimeyi kullandıysanız , hata derleme zamanında yakalanır.


65
btw "Değişken testine atamanın bir etkisi yok"
uyarısını göreceksiniz

12
@AvrDragon Ancak uyarıyı da göz ardı edebiliriz. Bu nedenle, son anahtar kelimeyi kullanarak alacağımız bir derleme hatası gibi ilerlememizi engelleyecek bir şeye sahip olmak her zaman daha iyidir.
Sumit Desai

10
@AvrDragon Bu geliştirme ortamına bağlıdır. Kötü alışkanlıklar geliştirmek istemiyorsanız, IDE'ye sizin için böyle şeyler yakalamak için güvenmemelisiniz.
b1nary.atr0phy

25
@ b1naryatr0phy aslında bu sadece bir derleyici uyarısı değil, sadece IDE ucu değil
AvrDragon 28:13

8
@SumitDesai "Ancak uyarıyı da göz ardı edebiliriz. Bu nedenle, son anahtar kelimeyi kullanarak alacağımız bir derleme hatası gibi ilerlememizi engelleyecek bir şeye sahip olmak her zaman daha iyidir." Demek istiyorum ki, bu, birçok Java geliştiricisinin katılmayacağını düşündüğüm çok güçlü bir ifade. Derleyici uyarıları bir nedenden dolayı var ve yetkili bir geliştirici, sonuçlarını düşünmeye 'zorlamak' için bir hataya ihtiyaç duymamalıdır.
Stuart Rossiter

127

Evet, anonim sınıflar, okunabilirlik ve niyet beyanı hariç neredeyse değersizdir. Bu üç şey değersiz mi?

Şahsen finalanonim bir iç sınıfta değişkeni kullanmadığım sürece yerel değişkenler ve parametreler için kullanma eğiliminde değilim, ancak parametre değerinin kendisinin değişmeyeceğini açıkça belirtmek isteyenlerin noktasını görebiliyorum (hatta atıfta bulunulan nesne içeriğini değiştirirse). Bunu okunabilirliğe ekleyenler için, bunun tamamen makul bir şey olduğunu düşünüyorum.

Demek istediğin kimse aslında iddia olsaydı daha önemli olacağını vermedi ama herhangi tür iddiaları görmeye hatırlayamıyorum - Ya etmezse bir şekilde veri sabit tutar. finalBunun gerçekten olduğundan daha fazla etkiye sahip olduğunu öne süren önemli bir geliştiriciler gövdesi olduğunu öneriyor musunuz?

EDIT: Gerçekten bir Monty Python referans ile tüm bunları özetlemiş olmalıydı; soru biraz "Romalılar bizim için ne yaptılar?" diye sormaya benzer.


17
Ama Krusty'yi danimarkalı ile açıklamak için, bizim için SONRA ne yaptılar ? =)
James Schek

Yuval. Bu komik! Sanırım barış kılıç kılıcıyla zorlansa bile olabilir!
gonzobrains

1
Sorusu "Ne, soran daha benzer görünüyor değil Romalılar bizim için yapılır?", Daha kesin anahtar kelime ne bir eleştiri olduğu için değil yapmak.
NobleUplift

"Finalin gerçekte olduğundan daha fazla etkiye sahip olduğunu öne süren önemli bir geliştiriciler grubu var mı?" Benim için o olduğunu asıl sorun: şiddetle buna değişmezliği zorlar düşünüyorum kullanan geliştiriciler önemli bir bölümü şüpheli arayanın değil mi zaman geçti öğeler. Tabii ki, daha sonra kodlama standartlarının kavramsal yanlış anlamaları ('yetkili' bir geliştiricinin bilmesi gereken) 'olup olmadığını' korumaya 'gerekip gerekmediği (ve daha sonra SO kapsamı dışındaki görüşlere yönelip geçmediği) tartışmasına girilir. tipi soru)!
Stuart Rossiter

1
@SarthakMittal: Gerçekten kullanmadığınız sürece değer kopyalanmayacak, eğer merak ediyorsanız.
Jon Skeet

76

Bana bir dava hakkında biraz açıklayalım var Jon önce bahsedildiği nihai kullanımı:

Yönteminizde anonim bir iç sınıf oluşturursanız ve bu sınıf içinde yerel bir değişken (bir yöntem parametresi gibi) kullanırsanız, derleyici sizi parametreyi sonlandırmaya zorlar:

public Iterator<Integer> createIntegerIterator(final int from, final int to)
{
    return new Iterator<Integer>(){
        int index = from;
        public Integer next()
        {
            return index++;
        }
        public boolean hasNext()
        {
            return index <= to;
        }
        // remove method omitted
    };
}

Burada fromve toparametrelerinin, anonim sınıf içinde kullanılabilmeleri için son olması gerekir.

Bu gereksinimin nedeni şudur: Yerel değişkenler yığın üzerinde yaşar, bu nedenle yalnızca yöntem yürütüldüğünde var olurlar. Ancak, anonim sınıf örneği yöntemden döndürülür, bu nedenle çok daha uzun süre yaşayabilir. Sonraki yöntem çağrıları için gerekli olduğundan yığını koruyamazsınız.

Java bunun yerine anonim sınıfa bu yerel değişkenlerin kopyalarını gizli örnek değişkenleri olarak koymaktır (bayt kodunu incelerseniz bunları görebilirsiniz). Ancak, nihai olmasalardı, anonim bir sınıf ve diğerinin değişken üzerinde yaptığı değişiklikleri görme yöntemi beklenebilir. İki kopya yerine yalnızca bir değişken olduğu yanılsamasını sürdürmek için, bunun nihai olması gerekir.


1
Beni "Ama eğer nihai değillerse ..." den kaybettin. Tekrar anlatmaya çalışabilir misin? Belki de yeterli kahvem yoktu.
hhafez

1
Yerel değişkenleriniz var - soru, yöntemin içinde anon sınıfı örneğini kullanırsanız ve bu nesnenin değerlerini değiştirirse ne olur - insanlar, tek bir değişken gördükleri için değişikliğin yöntemde görünür olmasını beklerler. Bu karışıklığı önlemek için nihai olmalı.
Michael Borgwardt

Bir kopya oluşturmaz, sadece referans verilen nesneye bir referanstır.
vickirk

1
@vickirk: referans türlerinde referansın bir kopyasını aldığından emin olun.
Michael Borgwardt

Btw, bu değişkenleri referans alan anonim sınıflarımız olmadığını varsayarsak final, HotSpot'un gözünde bir işlev parametresi ile son olmayan bir işlev parametresi arasında herhangi bir fark olup olmadığını biliyor musunuz?
Pacerier

25

Finali her zaman parametrelerde kullanıyorum.

Bu kadar ekliyor mu? Pek sayılmaz.

Kapatır mıyım? Hayır.

Nedeni: İnsanların özensiz kod yazdığı ve erişimcilerde üye değişkeni ayarlayamadığı 3 hata buldum. Tüm hataların bulunması zor oldu.

Bunun gelecekteki bir Java sürümünde varsayılanı yaptığını görmek istiyorum. Değer / referansa göre geçiş, çok sayıda genç programcıyı açar.

Bir şey daha .. yöntemlerim düşük sayıda parametreye sahip olma eğilimindedir, bu nedenle yöntem bildirimindeki fazladan metin bir sorun değildir.


4
Ben de bunu önermek üzereydim, bu final gelecekteki sürümlerde varsayılan olacak ve "mutable" ya da daha iyi tasarlanmış anahtar kelime belirtmek zorunda. İşte bununla
Jeff Axelrod

Uzun zaman oldu, ama yakaladığınız hataya bir örnek verebilir misiniz?
user949300

Cevap için en çok oylananlara bakın. Üye değişkeninin ayarlanmadığı ve bunun yerine parametrenin değiştirildiği gerçekten iyi bir örneği var.
Fortyrunner

18

Bir method parametresinde final kullanmanın, arayan taraftaki bağımsız değişkene ne olduğu ile ilgisi yoktur. Yalnızca bu yöntemin içinde değişmediği anlamına gelir. Daha işlevsel bir programlama tarzı benimsemeye çalışırken, bunun içindeki değeri görüyorum.


2
Tam olarak, fonksiyon arayüzünün bir parçası değil, sadece uygulama. Java'nın final arabirimlerdeki parametreler üzerinde izin verdiği (ancak dirsregards) kafa karıştırıcı / soyut yöntem bildirimleri kafa karıştırıcıdır .
Beni Cherniavsky-Paskin

8

Şahsen ben parametre parametrelerine final kullanmıyorum, çünkü parametre listelerine çok fazla karmaşa ekliyor. Yöntem parametrelerinin Checkstyle gibi bir şeyle değiştirilmemesini tercih ederim.

Mümkün olduğunca final kullandığım yerel değişkenler için Eclipse'nin kişisel projeler için kurulumumda bunu otomatik olarak yapmasına bile izin verdim.

Kesinlikle C / C ++ const gibi daha güçlü bir şey istiyorum.


IDE ve araç referanslarının OP kaydı veya konu için geçerli olduğundan emin değilim. Yani "son", referansın değiştirilmediğini / soyulmadığını bir derleme zamanı kontrolüdür. Ayrıca, bu tür şeyleri gerçekten zorlamak için, nihai referansların çocuk üyelerine karşı herhangi bir korumaya ilişkin cevaba bakınız. Örneğin bir API oluştururken, bir IDE veya araç kullanmak harici taraflara bu kodu kullanma / genişletme konusunda yardımcı olmaz.
Darrell Teague

4

Java, argümanların kopyalarını geçtiğinden, alaka düzeyinin finaloldukça sınırlı olduğunu hissediyorum . Sanırım bu alışkanlık, referans içeriğinin değiştirilerek değiştirilmesini engelleyebileceğiniz C ++ döneminden geliyor const char const *. Bu tür şeylerin, geliştiricinin doğası gereği aptal olduğuna ve gerçekten yazdığı her karaktere karşı korunması gerektiğine inanmasına neden olduğunu hissediyorum. Tüm alçakgönüllülük diyebilirim ki, atlamama rağmen çok az hata yazıyorum final(birisinin yöntemlerimi ve sınıflarımı geçersiz kılmasını istemiyorsam). Belki de sadece eski okul geliştiricisiyim.


1

Asla bir parametre listesinde final kullanmıyorum, sadece önceki katılımcıların söylediği gibi karmaşa ekliyor. Ayrıca Eclipse'de, bir parametre listesindeki final'i kullanmak benim için oldukça gereksiz görünecek şekilde bir hata oluşturmak için parametre atamasını ayarlayabilirsiniz. İlginç bir şekilde üzerinde hata üreten parametre atama için Eclipse ayarını etkinleştirdiğimde (Bu sadece gerçek kodu değil, akışı hatırlamak nasıl olduğunu): -

private String getString(String A, int i, String B, String C)
{
    if (i > 0)
        A += B;

    if (i > 100)
        A += C;

    return A;
}

Şeytanın avukatı oynamak, bunu yapmanın tam olarak nesi yanlış?


Bir IDE'yi bir çalışma zamanı JVM'sinden ayırmak için dikkatli olun. IDE, bir değişkenin yeniden atanmaması, ancak yanlışlıkla yapılması amaçlandığı zaman koddaki bir kusur gibi üye değişken soyulmasına karşı kod eklemek için derlenmiş bayt kodu sunucuda çalıştığında önemsizdir. son anahtar kelime.
Darrell Teague

1

Kısa cevap: final biraz yardımcı olur ama ... istemci tarafında savunma programlaması kullanın.

Gerçekten de sorun, finalsadece referansın değişmeden uygulanmasını sağlamasıdır; bu durum, arayan nesneden habersiz olarak referans alınan nesne üyelerinin mutasyona uğramasına izin verir. Bu nedenle, bu konuda en iyi uygulama, arayan taraftaki savunma programlamasıdır ve vicdansız API'lar tarafından ele geçirilme tehlikesi olan nesnelerin derinden değişmez örnekleri veya derin kopyaları oluşturur.


2
"final ile ilgili sorun sadece referans değişmeden zorlamasıdır " - Untrue, Java kendisi bunu önler. Bir yönteme iletilen bir değişkenin başvurusu bu yöntemle değiştirilemez.
Madbreaks

Lütfen göndermeden önce araştırın ... stackoverflow.com/questions/40480/…
Darrell Teague

O referanslarına referanslar değiştirilemez bu doğru olsaydı Basitçe savunma-kopyalama, değişmezlik edilmesinin söz, final anahtar, vb gerek yok olurdu, koyun
Darrell Teague

Ya beni yanlış anlıyorsun ya da yanılıyorsun. Bir yönteme bir nesne başvurusu iletir ve bu yöntem yeniden atarsa, yöntem yürütülmesini tamamladığında özgün başvuru (me) arayan için sağlam kalır. Java kesinlikle tam bir değerdir. Ve hiçbir araştırma yapmadığımı iddia etmek için acımasızca küstahsınız.
Madbreaks

Aşağı oylama çünkü op neden son kullanıldığını sordu ve sadece bir yanlış sebep verdiniz.
Madbreaks

0

Parametre bildirimlerine final eklemek için ek bir neden, "Ayıklama Yöntemi" yeniden düzenleme işleminin bir parçası olarak yeniden adlandırılması gereken değişkenleri tanımlamaya yardımcı olmasıdır. Büyük bir yöntem yeniden düzenleme başlamadan önce her parametreye final eklemenin hızla devam etmeden önce ele almam gereken herhangi bir sorun olup olmadığını söylediğini gördüm.

Ancak, yeniden düzenleme işleminin sonunda genellikle gereksiz olarak kaldırırım.


-1

Michel'in gönderisini takip edin. Ben kendim bunu açıklamak için başka bir örnek yaptım. Umarım yardımcı olabilir.

public static void main(String[] args){
    MyParam myParam = thisIsWhy(new MyObj());
    myParam.setArgNewName();

    System.out.println(myParam.showObjName());
}

public static MyParam thisIsWhy(final MyObj obj){
    MyParam myParam = new MyParam() {
        @Override
        public void setArgNewName() {
            obj.name = "afterSet";
        }

        @Override
        public String showObjName(){
            return obj.name;
        }
    };

    return myParam;
}

public static class MyObj{
    String name = "beforeSet";
    public MyObj() {
    }
}

public abstract static class MyParam{
    public abstract void setArgNewName();
    public abstract String showObjName();
}

Yöntem yukarıda kod, Dan thisIsWhy () , aslında atamadı [argüman myObj obj] a gerçek referans myParam içinde. Bunun yerine, MyParam içindeki yöntemde sadece [MyObj obj argümanını] kullanıyoruz.

Ama biz yöntemi bitirdikten sonra thisIsWhy () , argüman (nesne) myObj hala var ki?

Olması gerektiği gibi biz hala yöntemi diyoruz ana görebileceğiniz çünkü görünüyor showObjName () ve ulaşması gerekmez obj . MyParam, yöntem zaten döndürülmüş olsa bile yöntem bağımsız değişkenini kullanmaya devam eder / ulaşır!

Java'nın bunu gerçekten nasıl başardığı bir kopya oluşturmak da MyParam nesnesindeki MyObj nesnesinin bağımsız bir referansıdır (ancak MyParam'daki resmi bir alan değildir, bu yüzden göremeyiz)

"ShowObjName" adını verdiğimizde, ilgili değeri almak için bu başvuruyu kullanır.

Fakat eğer argümanı nihai olarak koymazsak, bu bir duruma yol açarsa, MyObj obj argümanına yeni bir bellek (nesne) atayabiliriz .

Teknik olarak hiçbir çatışma yok! Bunu yapmamıza izin verilirse, durum şu olacaktır:

  1. Artık MyParam nesnesinde artık [Yığındaki A Belleği] 'nin gizli bir [MyObj obj] işaretine sahibiz.
  2. Ayrıca bir başka [MyObj obj] var, ki bu [yığın B'de Bellek] şimdi thisIsWhy yönteminde yaşıyor.

Çatışma yok, ama "CONFUSING !!" Çünkü hepsi "obj" olan aynı "referans adını" kullanıyor .

Bundan kaçınmak için, programlayıcının "hataya meyilli" kodunu yapmasını önlemek için "son" olarak ayarlayın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.