Dış Java sınıfları neden iç sınıf özel üyelerine erişebilir?


177

Dış sınıfların iç sınıflara özel örnek değişkenlerine erişebildiğini gözlemledim. Bu nasıl mümkün olabilir? İşte bunu gösteren bir örnek kod:

class ABC{
    class XYZ{
        private int x=10;
    }

    public static void main(String... args){
        ABC.XYZ xx = new ABC().new XYZ();
        System.out.println("Hello :: "+xx.x); ///Why is this allowed??
    }
}

Bu davranışa neden izin verilir?


Bu soru, makinemde neden xx.x'e erişemediğimi açıklayan yorumu görene kadar beni bir süre karıştırdı ..
Wang Sheng

4
Yorumlar beni şaşırttı, Java 8 yukarıdaki kodu çalıştırın, derlemek ve çalıştırmak. xx.x dosyasına erişilebilir.
leon

Harish, kabul edilen cevabı (sorduğunuz soruya cevap vermeyen) lütfen kabul etmeyin ve bunun yerine Martin Andersson'un aşağıda verilen cevabı çok iyi cevaplar mısınız?
temporary_user_name

FWIW bu sözdizimi kesinlikle korkunç:new ABC().new XYZ()
Josh

Yanıtlar:


80

İç sınıf, gerçekten orijinal dış sınıfa ait bazı işlevleri temiz bir şekilde ayırmanın bir yoludur. 2 gereksiniminiz olduğunda kullanılmak üzere tasarlanmıştır:

  1. Dış sınıfınızdaki bazı işlevler, ayrı bir sınıfta uygulanmış olsaydı daha açık olurdu.
  2. Ayrı bir sınıfta olmasına rağmen, işlevsellik dış sınıfın çalışma şekline çok yakından bağlıdır.

Bu gereksinimler göz önüne alındığında, iç sınıflar dış sınıflarına tam erişime sahiptir. Temel olarak dış sınıfın bir üyesi oldukları için, dış sınıfın yöntemlerine ve niteliklerine - ayrıcalıklar dahil- erişimleri mantıklıdır.


217
Bu cevap, iç içe sınıfların neden dış sınıflarının özel üyelerine erişebildiğini açıklar. Ancak asıl soru, dış sınıfın neden iç içe sınıfların özel üyelerine erişimi olduğudur.
Andrew

13
Sadece "ve tersini" ekleyin Bu gereksinimler göz önüne alındığında, iç sınıflar kendi dış sınıflarına tam erişime sahiptir ve şimdi soruyu cevaplamaktadır.
anthropomo

13
Bu, bu sorunun doğru cevabı değil, burada: stackoverflow.com/questions/19747812/…
Colin Su

4
@anthropomo: Hayır, değil. Her iki gereklilik, dış sınıf, iç sınıfların özel üyelerine erişemeden mükemmel bir şekilde mümkündür.
VEYA Haritacı

Bunun özellikle yararlı olduğu iyi bir örnek Buildover Pattern, stackoverflow.com/a/1953567/1262000'dir . Üst sınıf, yalnızca bir Oluşturucu alan ve tüm üye değişkenlerine erişen bir kurucuya ihtiyaç duyar. Aksi takdirde, üst sınıfta tüm özel üye değişkenleri olan özel bir kurucuya sahip olmanız gerekir.
vikky.rk

62

İç sınıfınızın özel üyelerini gizlemek isterseniz, genel üyelerle bir Arabirim tanımlayabilir ve bu arabirimi uygulayan anonim bir iç sınıf oluşturabilirsiniz. Feryat örneği:

class ABC{
    private interface MyInterface{
         void printInt();
    }

    private static MyInterface mMember = new MyInterface(){
        private int x=10;

        public void printInt(){
            System.out.println(String.valueOf(x));
        }
    };

    public static void main(String... args){
        System.out.println("Hello :: "+mMember.x); ///not allowed
        mMember.printInt(); // allowed
    }
}

Bu mükemmel bir kod pasajı. Tam ihtiyacım olan şey. Teşekkürler!
kevinarpe

Lütfen çalıştırılabilecek kodu sağlayın. Dahası, lütfen özel değişkenin erişmesine izin verilmemesinin nedenini lütfen unutmayın.
androidyue

7
Ama sonra ... iç sınıf anonimdir. Bu iç sınıfın birkaç örneğini oluşturamaz veya bu iç sınıfı değişken bildirimler vb. İçin kullanamazsınız.
VEYA Eşleştirici

@VEYA Mapper bu yüzden xburada herkese açık olsa bile , buna izin verilmiyor mMember.x.
MAC

54

İç sınıf (erişim kontrolü amacıyla) içeren sınıfın bir parçası olarak kabul edilir. Bu, tüm ayrıcalıklara tam erişim anlamına gelir.

Bunun gerçekleştirilme şekli sentetik paket korumalı yöntemler kullanmaktır: İç sınıf, aynı pakette (ABC $ XYZ) ayrı bir sınıfa derlenecektir. JVM bu yalıtım düzeyini doğrudan desteklemez, böylece bayt kodu düzeyinde ABC $ XYZ, dış sınıfın özel yöntemlere / alanlara ulaşmak için kullandığı paket korumalı yöntemlere sahip olacaktır.


17

Buna benzer başka bir soruda doğru bir cevap var: İç içe bir sınıfın özel üyesine neden kapalı sınıfın yöntemleri ile erişilebilir?

JLS'de özel kapsam belirleme tanımı var - Erişilebilirliği Belirleme :

Aksi takdirde, üye veya kurucu özel olarak bildirilirse, ancak yalnızca üyenin veya kurucunun bildirimini kapsayan üst düzey sınıfın (§7.6) gövdesi içinde gerçekleşirse erişime izin verilir.


Sanırım bu pasaj soruma güzel cevap verebilir.
shen

5

İç sınıflar için bir IMHO önemli kullanım örneği fabrika modelidir. Çevreleyen sınıf, erişim kısıtlamaları olmadan iç sınıfın bir örneğini hazırlayabilir ve örneği özel erişimin onurlandırılacağı dış dünyaya iletebilir.

Çelişki için ise abyx aşağıda gösterildiği gibi sınıf statik ilan kapsayan sınıfına değil değişim erişim kısıtlamaları yapar. Aynı çevreleme sınıfındaki statik sınıflar arasındaki erişim kısıtlamaları da çalışır. Şaşırmıştım ...

class MyPrivates {
    static class Inner1 { private int test1 = 2; }
    static class Inner2 { private int test2 = new Inner1().test1; }

    public static void main(String[] args) {
        System.out.println("Inner : "+new Inner2().test2);
    }
}

1
Güzel yorum ama cevap yok.
ceving

@cerving Aslında bu tuhaf tasarım kararının pratik bir gerçek kullanımını görmemi sağlayan tek cevap. Soru, neden bu şekilde karar verildiğiydi ve bu büyük bir akıl yürütmedir - dış sınıfın iç sınıfta erişmesini isteyebileceğiniz şey ile diğer ilişkisiz sınıfların erişmesini istediğiniz arasındaki farkın bir gösterimi.
et_l

3

Erişim kısıtlamaları sınıf başına yapılır. Sınıfta bildirilen bir yöntemin tüm örnek / sınıf üyelerine erişememesi mümkün değildir. Bu, iç sınıfların aynı zamanda dış sınıfın üyelerine de serbest erişimi olmasını ve dış sınıfın, iç sınıfın üyelerine serbest erişiminin olmasını gerektirir.

Bir sınıfı başka bir sınıfın içine koyarak, onu uygulamaya sıkı sıkıya bağlı hale getirmiş olursunuz ve uygulamanın bir parçası olan her şeyin diğer bölümlere erişimi olmalıdır.


3

İç sınıfların ardındaki mantık, bir dış sınıfta bir iç sınıf yaratırsanız, bunun nedeni birkaç şeyi paylaşmaları gerektiğidir ve bu nedenle "normal" sınıflardan daha fazla esnekliğe sahip olmaları mantıklıdır.

Sizin durumunuzda, sınıfların birbirlerinin iç işleyişini görebilmeleri mantıklı değilse - bu temelde iç sınıfın sadece düzenli bir sınıf olabileceği anlamına gelirse, iç sınıfı olarak ilan edebilirsiniz static class XYZ. kullanmastatic , devleti paylaşmayacakları anlamına gelir (ve örneğin new ABC().new XYZ()işe yaramaz ve kullanmanız gerekir new ABC.XYZ().)
Ancak, durum buysa, XYZgerçekten bir iç sınıf olup olmayacağını ve belki de kendi sınıfını hak edip etmediğini düşünmelisiniz. Bazen statik bir iç sınıf oluşturmak mantıklıdır (örneğin, dış sınıfınızın kullandığı bir arabirimi uygulayan ve bu başka bir yerde yardımcı olmayacak küçük bir sınıfa ihtiyacınız varsa). bir dış sınıf haline getirilmiş olmalıydı.


2
Dış sınıf erişebilir özel üyelerini statik bununla ilgisi yok bu yüzden, tıpkı iyi iç sınıflar statik . "Sınıfların birbirlerinin iç işleyişini görebilmeleri mantıklı değil" diyorsunuz, ama durum böyle değil - ya sadece iç sınıfın dış sınıfın iç işleyişini görmesi mantıklıysa, tersi?
VEYA Haritacı

3

Thilo iyi bir şey ekledi cevap , "Bu nasıl mümkün olabilir?" İlk sorunuza . İkinci sorulan soruya biraz ayrıntı vermek istiyorum: Bu davranışa neden izin veriliyor?

Yeni başlayanlar için, bu davranışın, tanım gereği statik olmayan iç içe tipler olan iç sınıflarla sınırlı olmadığını açıkça görelim. Statik olması ve kapalı bir örneği bulunamayan iç içe geçmiş numaralandırmalar ve arabirimler dahil olmak üzere tüm iç içe geçmiş türler için bu davranışa izin verilir. Temel olarak, model aşağıdaki ifadeye göre bir sadeleştirmedir: İç içe kod, kapalı koda tam erişime sahiptir ve tersi de geçerlidir.

Öyleyse neden? Bence bir örnek konuyu daha iyi gösteriyor.

Bedeninizi ve beyninizi düşünün. Kolunuza eroin enjekte ederseniz, beyniniz yükselir. Eğer beyninizin amigdala bölgesi, kişisel güvenliğiniz için bir tehdit olduğuna inandığını görürse, örneğin bir yaban arısı deyin, vücudunuzu diğer yöne çevirip tepeler için iki kez "düşünmeden" koşturur.

Böylece, beyin vücudun içsel bir parçasıdır - ve garip bir şekilde, tam tersi de. Bu tür yakından ilişkili kuruluşlar arasındaki erişim kontrolünü kullanmak, ilişki iddialarını kaybeder. Erişim kontrolüne ihtiyacınız varsa, sınıfları daha farklı birimlere ayırmanız gerekir. O zamana kadar aynı birim. İleri çalışmalar için itici bir örnek, bir Java'nın Iteratorgenellikle nasıl uygulandığına bakmak olacaktır .

Kapalı koddan iç içe koda sınırsız erişim, çoğunlukla iç içe tipteki alanlara ve yöntemlere erişim değiştiricileri eklemek için işe yaramaz hale getirir. Bunu yapmak dağınıklığı arttırır ve Java programlama dilinin yeni kullanıcıları için yanlış bir güvenlik duygusu sağlayabilir.


1
Bu gerçekten kabul edilen cevap olmalıdır. Çok açık ve eksiksiz. Bunun yerine, kabul edilen cevap soruyu bile ele almaz.
temporary_user_name

IMO hala dış sınıfın doğrudan erişemediği bir iç sınıfa neden kolayca özel alanlar ekleyemediğimize dair soruya cevap vermiyor. Yanılmıyorsam, bu iç sınıflar için birincil vakalardan birini mahveder - kısa ömürlü "yapı benzeri", değişmez tipler yaratır. FWIW C # bunu memnuniyetle destekliyor: repl.it/repls/VengefulCheeryInverse
Josh

-1

İç sınıf, Dış sınıfın bir özniteliği olarak kabul edilir. Bu nedenle, Inner sınıfı örnek değişkeni özel olsun ya da olmasın, Dış sınıf, tıpkı diğer özel özniteliklerine (değişkenleri) erişmek gibi sorunsuzca erişebilir.

class Outer{

private int a;

class Inner{
private int b=0;
}

void outMethod(){
a = new Inner().b;
}
}

-2

Senin Çünkü main()yöntem olduğu ABCsınıfın, olabilir , kendi iç sınıf erişmek.


2
Soru, ABCsınıf üyelerinin sınıfta yuvalanmış sınıflara erişip erişemeyeceği ABCdeğil , Java'da sınıfta yuvalanmış sınıfların özel üyelerine neden erişebildikleri değil ABC.
VEYA Haritacı

Soruyu aynı gün sordum. Birisi soruyu 2 yıl sonra düzenledi ve aşağı oylama 3 yıl sonra geldi. Soruyu düzenleyen her kimse, sorunun ifadesini tamamen değiştirdiğinden eminim.
aberrant80
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.