2009-04-18 13 views
32

İç sınıf örneğim varsa, dış sınıfına iç sınıfında olmayan koddan nasıl erişebilirim? İç sınıfta, dış sınıfa ulaşmak için Outer.this kullanabilirim, ama bunu elde etmenin herhangi bir dış yolunu bulamıyorum. ÖrneğinJava'da, iç sınıfta olmadığım zaman dış sınıfa nasıl erişebilirim?

:

public class Outer { 
    public static void foo(Inner inner) { 
    //Question: How could I write the following line without 
    // having to create the getOuter() method? 
    System.out.println("The outer class is: " + inner.getOuter()); 
    } 
    public class Inner { 
    public Outer getOuter() { return Outer.this; } 
    } 
} 
+0

Eğer çözme ne gibi sorunlar açıklayabilir? Yoksa bu akademik mi? Esas olarak, –

+0

Akademik. Buna bir cevapla geldiğimde karşılaştım: http://stackoverflow.com/questions/763359/validating-instances-of-inner-classes/763504 İki cevap verdim, biri OP'nin kullanmak istediğini yapıyordu. Yukarıda kullandığım aynı geçici çözüm (getOuter() yöntemi). Ama benim diğer cevabımda (oyulmuş olanı) bunu farklı bir şekilde tasarladım ki, bu gerekli değildi. Ama bunu yapmanın mümkün olup olmadığını merak ediyordum. – Kip

+1

Sağlanan örnek, bu sorunun en iyi cevabıdır. – Pindatjuh

cevap

32

Outer$Inner sınıfının bayt kodu, this$0 türünde Outer türünde paket kapsamlı bir alan içerecektir. Bu, statik olmayan iç sınıfların Java'da nasıl uygulandığıdır, çünkü bayt kodu düzeyinde bir iç sınıf kavramı yoktur.

Gerçekten istiyorsanız, bu alanı yansımayı kullanarak okuyabiliyor olmalısınız. Bunu yapmaya hiç ihtiyacım olmadı, bu yüzden tasarımı değiştirmeniz gerekmediği için en iyisi olurdu.

Örnek kodunuz yansıma kullanırken nasıl görünecektir. Bu çok çirkin. ;)

public class Outer { 
    public static void foo(Inner inner) { 
     try { 
      Field this$0 = inner.getClass().getDeclaredField("this$0"); 
      Outer outer = (Outer) this$0.get(inner); 
      System.out.println("The outer class is: " + outer); 

     } catch (NoSuchFieldException e) { 
      throw new RuntimeException(e); 
     } catch (IllegalAccessException e) { 
      throw new RuntimeException(e); 
     } 
    } 

    public class Inner { 
    } 

    public void callFoo() { 
     // The constructor of Inner must be called in 
     // non-static context, inside Outer. 
     foo(new Inner()); 
    } 

    public static void main(String[] args) { 
     new Outer().callFoo(); 
    } 
} 
+2

Bu (IIRC) derleyicisine bağımlıdır ve genel olarak bir setAccessible'a ihtiyacınız olacaktır. –

+0

Sanırım (çok fazla tempolu arama), bu alanın isimlendiricisi bile derleyiciye bağımlıdır, yani başka bir derleyiciyle bu hacklemeyi denerseniz * sorun olabilir. –

+0

Pratikte Java Concurrency'ı okuyorum ve örneklerden biri, iç sınıfın bir örneğini yapıcıdaki bazı yabancı kodlara aktarırsak, bu referansın iç sınıfla nasıl kaçabileceğini gösterdi. Ve yapıcı dönmeden önce referansta bekletilen yabancı kodu yazmaya çalışıyorum. Cevabınız için çok teşekkürler. –

14

tasarım gereği, hiçbir yolu yoktur. Eğer iç sınıfa ait bir örnek üzerinden dış sınıfa erişmeniz gerekiyorsa, tasarımınız geriye doğrudur: iç sınıfların noktası genellikle sadece dış sınıfta veya bir arabirim üzerinden kullanılır.

+2

Bu benim de fikrimdi, ama bu sınırlamaya hitap eden herhangi bir belge bulamıyorum. Resmi bir şey bulursanız bu cevabı memnuniyetle kabul ediyorum. – Kip

+0

Açıkça bir "sınırlama" değil - belirli bir (daha ziyade) belirsizliğin ABSENCE'ı hakkında neden belgelendirilmeli? –

+2

15.8.3 ve 15.8.4 bunu kapsamaktadır. "Sözcüksel olarak kapsanan herhangi bir örnek, bu anahtar kelimeyi açık bir şekilde nitelendirerek ifade edilebilir." Sorunun sözlerinde, sözdizimi kapalı bir örnek değildir. –

8

Dış sınıfa erişmeniz gerektiğinde bir getter eklemenin nesi yanlış? Bu şekilde erişime izin verilip verilmediğini kontrol edebilirsiniz.

0

sadece böyle bir şey yapamaz:

Bir (statik olmayan) iç sınıf var ise
public static class Inner { // static now 
    private final Outer parent; 

    public Inner(Outer parent) { this.parent = parent; } 

    public Outer get Outer() { return parent; } 
} 
+3

Statik kullanımı kaldırın ve kullanın: Dış getOuter() {return Outer.this; –

1

, o zaman konum tanımı gereği bir şey ile çalışan bu kapatmakta içeride sadece fonksiyonlar dış sınıfın içeriği. Yani iç sınıfa bir sapı elde etmek için, onu dışsal örnek üzerinden almış olmalısınız. Yani, böyle bir erişimciye ihtiyaç duyacağınız noktaya ulaşmak için görebildiğim tek yol, dış ref içerisinden içten içeri girip dış örnek referansını kaybetmiş veya atmıştır. Örneğin

:

public class Outer{ 
    public class Inner { 
    } 
} 

public class UsesInner{ 
Collection<Outer.Inner> c = new ArrayList<Outer.Inner>(); 
} 

Şimdi c doldurmak tek yolu Dış() örneklerini oluşturmaktır. Bunun gibi bir şey için yararlı bir amaç görmeyi merak ederdim.

+0

Dürüst olmak gerekirse, iyi bir neden de düşünemiyorum.Sadece bu soruya cevap vermeye çalıştım: http://stackoverflow.com/questions/763359/validating-instances-of-inner-classes/763504 Bu durumda, içsel bir sınıfın var olduğundan emin olmak istedim. dış sınıfın özel örneği. Başka bir cevapta, sadece iç sınıftaki yöntemi tanımlaması gerektiğini, böylece bir problem olmayacağını önerdim. Ama yine de, yapmanın yolu olup olmadığını merak ettim. – Kip

1

Bu davranışı istemenin bir nedeni şöyledir: İç sınıf örneğiniz var ve yansıtma kullanarak dış sınıfta tanımlanan bir yönteme erişmeniz gerekiyor.

Kayıt için "inner.getClass(). GetDeclaredField (" bu $ 0 ")" çalışır. Alan özel olduğu için, ayrıca, field.setAccessible (true) öğesini çağırmanız gerekir.

6

bir Innner sınıf payının iki ayrı örneklerini Outer sınıfı (== aynı örneği veya bağlama bağlı eşittir örneğin, kontrol etmek gerekiyor, bu, aslında, çok iyi bir sorudur).

Ben genel amaçlı bir arayüz yapmak öneririm (kesinlikle adlandırılmış iç sınıflar için gereken ancak "instancedof"/için demir olabilir değil): Herhangi adlandırılmış iç sınıfa uygulanabilir

public interface InnerClass<Outer> { 
    Outer getOuter(); 
} 

.

Sonra böyle bir şey yapmak:

class MyInnerClass implements InnerClass<Outer> { 
    Outer getOuter() { 
     return Outer.this; 
    } 
    // remaining implementation details 
} 

ve bu yolu InnerClass<Outer> arabirimini uygulayan herhangi bir iç sınıfından dış sınıf erişmek (ve aslında bunu uygulayan kontrol edin) olabilir. İçinizdeki sınıf anonim ise

, sadece (onun örnek için Zengin MacDonald sayesinde) yapabilirsiniz:

new InterfaceOrAbstractClass<Outer>() { 
    Outer getOuter() { // super inefficient but this is the only way ! 
     return (Outer)getClass().getDeclaredField("this$0"); 
    } 
    /* other methods */ 
} 

ama InterfaceOrAbstractClasszorunluluk anonim ait getOuter() dışında erişmek mümkün InnerClass<Outer> uygular sınıf gövdesi!

Javac, TÜM iç sınıflarda otomatik olarak bir tür InnerClass<Outer> arabirimini uyguladıysa ve çok daha kolay anonim sınıflarda bile (bu da sorunsuz iç işleme yok) yapabilirse çok daha kolay olurdu!

1

Bu sorunu yazmak için sorun nerede?

class OuterClass{ 
class InnerClass{ 
    OuterClass outerClass = OuterClass.this; 
} 

}

+4

Yazmanın yolu, bunun bir cevap mı yoksa yeni bir soru mu olduğunu söylemek zor. – Eric

İlgili konular