Java'da anonim iç sınıfları statik yapmak mümkün müdür?


123

Java'da yuvalanmış sınıflar olabilir staticveya olmayabilir. Öyleyse static, içeren örneğin işaretçisine bir başvuru içermezler (artık iç sınıflar olarak da adlandırılmazlar, iç içe sınıflar olarak adlandırılırlar).

staticBu referansa ihtiyaç duymadığında yuvalanmış bir sınıf oluşturmayı unutmak , çöp toplama veya kaçış analizinde sorunlara yol açabilir.

Anonim bir iç sınıf yapmak da mümkün mü static? Yoksa derleyici bunu otomatik olarak mı anlar (ki bu olabilir, çünkü herhangi bir alt sınıf olamaz)?

Örneğin, anonim bir karşılaştırıcı yaparsam, neredeyse hiçbir zaman dışarıdan referansa ihtiyacım olmaz:

  Collections.sort(list, new Comparator<String>(){
       int compare(String a, String b){
          return a.toUpperCase().compareTo(b.toUpperCase());
       }
  }

Bir iç sınıfı statik yapmayı unuttuğunuzda "çöp toplama veya kaçış analizi" ile ilgili sorunlar nelerdir? Bunun sadece performansla ilgili olduğunu sanıyordum ...
Tim Büthe

17
İç sınıf örneğiniz, ihtiyacınız olmasa bile dış örneğine bir başvuruyu canlı tutar. Bu, eşyaların çöp toplanmasını önleyebilir. Bir şeyin hafif örneklerini oluşturan (kaynak ağırlıklı) bir fabrika nesnesini hayal edin. Fabrika işini yaptıktan sonra (örn. Uygulama başlangıcı sırasında), imha edilebilir, ancak bu yalnızca yarattığı şeyler geri bağlanmıyorsa çalışır.
Thilo

Biliyorum, bu sadece bir örnek, ancak yinelenen bir örnek olduğu için, Collections.sort(list, String.CASE_INSENSITIVE_ORDER)Java 2'den beri çalıştığından bahsetmek gerekir , okuyun, çünkü Koleksiyon API var…
Holger

Yanıtlar:


138

Hayır, yapamazsınız ve hayır, derleyici çözemez. Bu nedenle FindBugs static, örtük thisreferanslarını kullanmazlarsa her zaman anonim iç sınıfları adlandırılmış iç içe sınıflara değiştirmeyi önerir .

Düzenleme: Tom Hawtin - tackline, anonim sınıf statik bir bağlamda (örneğin mainyöntemde) yaratılırsa, anonim sınıfın aslında olduğunu söylüyor static. Ancak JLS aynı fikirde değil :

Anonim bir sınıf asla abstract(§8.1.1.1) değildir. Anonim bir sınıf her zaman bir iç sınıftır (§8.1.3); asla değildir static(§8.1.1, §8.5.1). Anonim bir sınıf her zaman finalörtüktür (§8.1.1.2).

Roedy Green'in Java Sözlüğü , anonim sınıflara statik bir bağlamda izin verildiği gerçeğinin uygulamaya bağlı olduğunu söylüyor :

Kodunuzu koruyanları şaşırtmak istiyorsanız, wags, anonim sınıfların asla olmadığını belirtmesine rağmen, init kodu ve yöntemleri javac.exeiçinde anonim sınıflara izin vereceğini keşfetti . Elbette bu anonim sınıfların nesnenin örnek alanlarına erişimi yoktur. Bunu yapmayı önermiyorum. Özelliği her an ayrılabildi.staticstaticstatic

Düzenleme 2: JLS, aslında §15.9.2'de statik bağlamları daha açık bir şekilde kapsar :

Örneklenen sınıf C olsun ve yaratılan örnek ben olayım. Eğer iç sınıftır sonra I , hemen bir kapatma örneği olabilir. Hemen çevreleyen i örneği (§8.1.3) aşağıdaki şekilde belirlenir.

  • Eğer C daha sonra anonim bir sınıf vardır:
    • Sınıf örneği oluşturma ifadesi statik bir bağlamda gerçekleşirse (§8.1.3), bu durumda i'nin hemen kapsayan bir örneği yoktur.
    • Aksi takdirde, i'nin hemen çevreleyen örneği olur this.

Dolayısıyla, statik bağlamdaki anonim bir staticsınıf, teknik olarak bir staticsınıf olmasa da, çevreleyen sınıfa bir başvuru tutmaması açısından iç içe geçmiş bir sınıfa kabaca eşdeğerdir .


19
FindBugs için +1 - her Java geliştiricisinin yapısında buna sahip olmalıdır.
Andrew Duffy

13
Bu çok talihsiz bir durumdur, çünkü bu, performans nedenlerinden ötürü neredeyse kısa sözdiziminden kaçınmak isteyebileceğiniz anlamına gelir.
Thilo

2
JLS 3rd Ed, statik bağlamlardaki iç sınıfların durumu ile ilgilenir. JLS anlamında statik değillerdir, ancak soruda verilen anlamda statiktirler.
Tom Hawtin - tackline

6
İşte nasıl: 's uygulama bağımlı bir örnek bu kod baskılar truejavac (güneş-jdk-1.7.0_10) kullanılarak ve falseEclipse derleyicisi kullanarak.
Paul Bellora

1
@MichaelMyers FindBug'ların 'bu' referansı kullanmadan Anonim İç Yapma konusunda beni uyarmasını simüle etmeye çalıştım ve hiçbir şey olmadı. Cevabınızın başında söylediğiniz gibi FindBugs'ın sizi nasıl uyardığını gösterebilir misiniz? Sadece bir bağlantı veya herhangi bir şey yapıştırın.
Thufir Hawat

15

Türü. Statik bir yöntemde oluşturulan anonim bir iç sınıf, açıkça statik olacaktır, çünkü bunun dışında bir kaynak yoktur.

Statik bağlamlardaki iç sınıflar ile statik iç içe geçmiş sınıflar arasında bazı teknik farklılıklar vardır. İlgileniyorsanız JLS 3. Basımı okuyun.


Aslında bunu geri alıyorum; JLS aynı fikirde değil. java.sun.com/docs/books/jls/third%5Fedition/html/… : "Anonim bir sınıf her zaman bir iç sınıftır; asla statik değildir."
Michael Myers

1
sorudakinden farklı bir anlamda statik.
Tom Hawtin - tackline

1
Biraz açıklama ekledim.
Tom Hawtin - tackline

15

Sanırım buradaki isimlendirmede biraz kafa karışıklığı var, ki bu kuşkusuz çok aptalca ve kafa karıştırıcı.

Onlara ne derseniz deyin, bu kalıplar (ve farklı görünürlükteki birkaç varyasyon) tüm olası, normal, yasal Java'dır:

public class MyClass {
  class MyClassInside {
  }
}

public class MyClass {
  public static class MyClassInside {
  }
}

public class MyClass {
  public void method() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

public class MyClass {
  public static void myStaticMethod() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

Dil spesifikasyonunda karşılanırlar (gerçekten rahatsızsanız, statik yöntemin içindekiler için bölüm 15.9.5.1'e bakın).

Ancak bu alıntı tamamen yanlış :

javac.exe, anonim sınıfların hiçbir zaman statik olmadığını belirtmesine rağmen, anonim sınıflara statik başlatma kodu ve statik yöntemler içinde izin verir

Sanırım alıntı yapılan yazar statik anahtar kelimeyi statik bağlamla karıştırıyor . (Kuşkusuz, JLS de bu açıdan biraz kafa karıştırıcı.)

Dürüst olmak gerekirse, yukarıdaki modellerin tümü iyidir (bunlara "iç içe", "iç", "anonim" ne derseniz ...). Gerçekte, kimse Java'nın bir sonraki sürümünde bu işlevi aniden kaldırmayacaktır. Gerçekten!


2
"(Kuşkusuz, JLS de bu açıdan biraz kafa karıştırıcı.)" Doğru anladın. Uygulamaya bağlı olduğunu söylemek kulağa garip geldi, ancak daha önce Java Sözlüğü'nde bariz bir hata gördüğümü hatırlamıyorum. Şu andan itibaren, onu biraz tuzla alıyorum.
Michael Myers

2
Aslında kalıpların hiçbirinden bahsetmiyoruz. Anonim iç içe geçmiş sınıfın statik olduğunu kastediyoruz. Yani arasında bir "statik" ekleyebilir newve JComponentüçüncü örnekte.
Timmmm

Orijinal soruya ne istediğini göstermek için bir açıklama ekledim.
Timmmm

@MichaelMyers, JLS'deki dikte her zaman yorumlanmalıdır.
Pacerier


0

anonim iç sınıflar hiçbir zaman statik değildir (statik yöntemleri veya nihai olmayan statik alanları bildiremezler), ancak statik bir bağlamda (statik yöntem veya statik alan) tanımlanmışlarsa, yapamayacakları anlamda statik olarak davranırlar. çevreleyen sınıfın statik olmayan (yani örnek) üyelerine erişim (statik bağlamdaki diğer her şey gibi)


-3

Anonim bir iç sınıfı statik bir yöntem içinde çağırarak statik hale getirme notu üzerine.

Bu aslında referansı kaldırmaz. Bunu, anonim sınıfı serileştirmeye çalışarak ve çevreleyen sınıfı serileştirilebilir hale getirmeden test edebilirsiniz.


5
-1: Statik bir yöntem içinde anonim bir sınıf oluşturma aslında gelmez dış sınıfa başvurusunu kaldırın. Bunu, anonim sınıfı serileştirmeye çalışarak ve çevreleyen sınıfı serileştirilebilir hale getirmeden test edebilirsiniz. (Az önce yaptım.)
Christian Semrau
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.