Java'da statik iç içe sınıf, neden?


217

Java koduna bakıyordum ve LinkedListstatik iç içe bir sınıf kullandığını fark ettim Entry.

public class LinkedList<E> ... {
...

 private static class Entry<E> { ... }

}

Normal bir iç sınıftan ziyade statik bir iç içe sınıf kullanmanın nedeni nedir?

Düşünebilmemin tek nedeni, Entry'nin örnek değişkenlere erişimi olmamasıydı, bu yüzden OOP açısından daha iyi kapsüllemeye sahipti.

Ama başka nedenler de olabilir, belki performans olabilir diye düşündüm. Ne olabilir?

Not. Umarım terimlerimi doğru bir şekilde anladım, bunu statik bir iç sınıf olarak adlandırırdım, ama bunun yanlış olduğunu düşünüyorum: http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html


Yanıtlar:


271

Bağlantı verdiğiniz Güneş sayfasında ikisi arasında bazı önemli farklar vardır:

İç içe sınıf, çevreleyen sınıfının bir üyesidir. Statik olmayan iç içe sınıflar (iç sınıflar), özel olarak bildirilmiş olsalar bile, kapalı sınıfın diğer üyelerine erişebilir. Statik iç içe sınıfların, kapalı sınıfın diğer üyelerine erişimi yoktur.
...

Not: Statik iç içe bir sınıf, diğer üst düzey sınıflarda olduğu gibi dış sınıfının (ve diğer sınıflarının) örnek üyeleriyle etkileşime girer. Gerçekte, statik iç içe geçmiş sınıf, davranışsal olarak, paketleme kolaylığı için başka bir üst düzey sınıfta iç içe geçmiş olan üst düzey bir sınıftır.

LinkedList.EntryÜst düzey sınıf olmasına gerek yoktur , çünkü sadece tarafından kullanılır LinkedList( aynı kavram Entryolarak adlandırılan statik iç içe sınıflara sahip başka arabirimler de vardır Map.Entry). LinkedList'in üyelerine erişmesi gerekmediğinden, statik olması mantıklıdır - çok daha temiz bir yaklaşımdır.

As Jon Skeet işaret , sana yuvalanmış sınıf statik olma ile başlamak olduğunu kullanılarak, ve gerçekten senin kullanımına dayalı olmayan statik olması gerekiyorsa o zaman karar eğer daha iyi bir fikir olduğunu düşünüyorum.


Bah, işe yorum için bir çapa bağlantısı alamıyorum gibi görünüyor , ama bu yorum:#comment113712_253507
Zach Lysobey

1
@matt b Statik iç içe bir sınıfın Outer sınıfının örnek üyelerine erişimi yoksa, Outer sınıfının örnek üyeleriyle nasıl etkileşime girer?
Geek

1
@mattb Ama @Geek nasıl fark etti, Güneş sayfası çelişkili: A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class Belgelerden önce sadece bir paragraf Static nested classes do not have access to other members of the enclosing class şöyle A nested (non-static) class interacts with the instance members of its outer class (and other classes) just like any other top-level class
diyorsa

1
@DavidS Bağlantı için teşekkürler! Evet, yanılmışım, yorumumu şimdi okuduğumda, sözlerimin yanlış olduğunu görüyorum. Dediğiniz gibi: An inner class interacts with the instance members through an implicit reference to its enclosing classve bu non-static inner classesda anonymous inner classesveya başka bir ilginç özelliğe dikkat çekiyor local classes defined inside a block: hepsi bir kurucuya sahip olamaz,no-arg çünkü derleyici , çevreleyen bir örneğin bir referansını iletmek için her kurucunun arg dizisini örtük olarak önleyecektir. sınıf. Gayet basit.
tonix

1
yalnızca özel yapıcıya sahip olan dış sınıfı başlatmak için statik iç sınıfı kullanabilirsiniz. Bu, yapıcı modelinde kullanılır. Aynı şeyi iç sınıfla yapamazsınız.
seenimurugan

47

Bana göre soru, bir iç sınıfı her gördüğünüzde tam tersi olmalıdır - bir örneğe ekstra karmaşıklık ve örtülü (açık ve net olmaktan ziyade, IMO) referansla gerçekten bir iç sınıf olması gerekir mi? içeren sınıfın?

Dikkat edin, bir C # hayranı olarak önyargılıyım - iç içe geçmiş türleri olmasına rağmen, C # iç sınıflara eşdeğer değil. Henüz iç dersleri özlediğimi söyleyemem :)


4
Yanılıyor olabilirim, ama bu bana içsel bir sınıf değil, statik iç içe bir sınıf örneği gibi geliyor. Hatta örnekte, iç içe sınıftaki çevreleyen sınıftaki örnek değişkenlere erişimlerinin olmadığını belirtirler.
ColinD

Evet, Colin'nin hakkı - C # iç sınıflara sahip değil, iç içe sınıflara sahip. Dikkat edin, C # 'daki statik iç içe bir sınıf, Java'daki statik iç içe bir sınıfla aynı değildir :)
Jon Skeet

2
Yuvalanmış türler, C # 'ın Java ile karşılaştırıldığında son derece doğru bulduğu alanlardan biridir. Ben her zaman onun anlamsal / mantıksal doğruluğuna hayret ediyorum ..
nawfal

3
@nawfal: Evet, birkaç niggles'i engelleme C # dilinin ne kadar iyi tasarlandığını (ve belirtildiğini) merak ediyorum.
Jon Skeet

1
@JonSkeet bu zencilerin ne olduğu hakkında bir makaleniz veya blogunuz var mı? Ben "niggles" olarak bulduğunuz aracılığıyla gitmek isterdim :)
nawfal

27

Burada dikkate alınması gereken açık olmayan bellek saklama sorunları vardır. Statik olmayan bir iç sınıf, 'dış' sınıfına örtük bir başvuruda bulunduğundan, iç sınıfın bir örneğine kuvvetle başvurulursa, dış örneğe de güçlü bir şekilde başvurulur. Bu, dış sınıf çöp toplanmadığında bazı şeylerin çizilmesine yol açabilir, ancak hiçbir şey referans vermediği görülüyor .


Eğer 'dış' sınıf kesindir ve bu nedenle somutlaştırılamazsa, bu argüman mantıklı mıdır? Çünkü dış sınıfa bir referansı olması / tutulması, sonuncusu ise işe yaramaz.
getsadzeg

10

Bir şey için, statik olmayan iç sınıflar, dış sınıf örneğini gösteren ekstra, gizli bir alana sahiptir. Eğer Giriş sınıfı statik olmasaydı, o zaman ihtiyaç duymadığı bir erişime sahip olmanın yanı sıra, üç yerine dört işaretçi taşıyordu.

Kural olarak, temelde orada veri sınıfının bir topluluğu olarak hareket edecek bir sınıf tanımlarsanız, C'deki bir "yapı" gibi, bunu statik yapmayı düşünün.


8

Statik iç sınıf yapıcı modelinde kullanılır. Statik iç sınıf, sadece özel yapıcıya sahip olan dış sınıfını somutlaştırabilir. Böylece, yalnızca özel yapıcıya sahip olan dış sınıfı somutlaştırmak için statik iç sınıfı kullanabilirsiniz. İç sınıfa erişmeden önce dış sınıfın nesnesini yaratmanız gerektiğinden, iç sınıfla aynı şeyi yapamazsınız.

class OuterClass {
    private OuterClass(int x) {
        System.out.println("x: " + x);
    }

    static class InnerClass {
        public static void test() {
            OuterClass outer = new OuterClass(1);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass.test();
        // OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
    }
}

Bu çıktı x: 1


7

statik iç içe sınıf, dış sınıf üyelerine erişimi olmadığı için diğer tüm dış sınıflar gibidir.

Sadece ambalaj kolaylığı için, statik iç içe geçmiş sınıfları okunabilirlik amacıyla tek bir dış sınıfta toplayabiliriz. Bunun dışında statik iç içe sınıfın başka bir kullanım durumu yoktur.

Bu tür kullanımlara örnek olarak Android R.java (kaynaklar) dosyasında bulabilirsiniz. Android res klasörü (ekran tasarımları içeren) düzenleri, çekilebilir klasör (proje için kullanılan görüntüleri içeren), değerler klasörü (dize sabitleri içeren), vb içerir.

Sine tüm klasörler Res klasörünün bir parçasıdır, android aracı dahili olarak iç klasörlerinin her biri için çok sayıda statik iç içe sınıflar içeren bir R.java (kaynaklar) dosyası oluşturur.

İşte android oluşturulan R.java dosyasının görünümü ve hissi: Burada sadece ambalaj kolaylığı için kullanıyorlar.

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.techpalle.b17_testthird;

public final class R {
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int main=0x7f070000;
    }
    public static final class string {
        public static final int action_settings=0x7f050001;
        public static final int app_name=0x7f050000;
        public static final int hello_world=0x7f050002;
    }
}


4

Basit örnek:

package test;

public class UpperClass {
public static class StaticInnerClass {}

public class InnerClass {}

public static void main(String[] args) {
    // works
    StaticInnerClass stat = new StaticInnerClass();
    // doesn't compile
    InnerClass inner = new InnerClass();
}
}

Statik olmayan bir sınıf, üst sınıfın bir örneğinde istisna olarak somutlaştırılamaz (bu nedenle main öğesinin statik bir işlev olduğu örnekte değil)


StaticInnerClass'ınız aslında statik bir iç / iç sınıf değildir. üst düzey bir statik sınıftır.
theRiley

2

Statik ve normalin nedenlerinden biri sınıf yüklemesi ile ilgilidir. Bir iç sınıfı üst öğesinin yapıcısında başlatamazsınız.

Not: Her zaman 'iç içe' ve 'iç' ifadelerinin birbirinin yerine geçebileceğini anladım. Terimler arasında ince nüanslar olabilir, ancak çoğu Java geliştiricisi de anlardı.


1

Statik olmayan iç sınıflar bellek sızıntılarına neden olurken, statik iç sınıf bunlara karşı koruma sağlar. Dış sınıf önemli miktarda veri içeriyorsa, uygulamanın performansını düşürebilir.


'statik iç' bir çelişkidir.
Lorne Marquis

1
@EJP, sheesh ... insanlar "statik iç sınıflar" dan bahsettiğinde bunu gerçekten işaret ederek insanlar ...
Sakiboy

0

Performans farkı hakkında bir bilgim yok, ama dediğin gibi, statik iç içe geçmiş sınıf, sınıfın bir örneğinin parçası değil. Gerçekten bir iç sınıf olması gerekmedikçe, statik bir iç içe sınıf oluşturmak daha basit görünüyor.

Biraz değişkenlerimi Java'da neden her zaman sonlandırıyorum gibi görünüyor - eğer nihai değilse, onlarla komik bir şeyler olduğunu biliyorum. Statik iç içe bir sınıf yerine bir iç sınıf kullanıyorsanız, bunun iyi bir nedeni olmalıdır.


İçsel bir sınıf da 'çevreleyen sınıfın bir örneğinin parçası' değildir.
Lorne Marquis

bir iç sınıf varoluş olarak çevreleyen sınıfa bağlıdır ve çevreleyen sınıfın üyelerine samimi bir erişime sahiptir, bu yüzden aslında çevreleyen sınıfın bir parçasıdır. aslında bir üyedir.
theRiley

0

Statik olmayan bir sınıftan ziyade statik bir iç içe sınıf kullanmak bazı durumlarda alan tasarrufu sağlayabilir. Örneğin: Comparatorbir sınıfın içinde bir uygulama uygulamak , örneğin Öğrenci.

public class Student {
  public static final Comparator<Student> BY_NAME = new ByName();
  private final String name;
  ...
  private static class ByName implements Comparator<Student> {
    public int compare() {...}
  }
}

Ardından, staticyeni bir öğrenci örneği oluşturulduğunda yeni bir tane oluşturmak yerine, Öğrenci sınıfının yalnızca bir Karşılaştırıcıya sahip olmasını sağlar.


-1

İç sınıf avantajı

  1. tek kullanımlık
  2. kapsüllemeyi destekler ve geliştirir
  3. Hassasiyet
  4. özel saha erişimi

Dış sınıfın varlığı olmadan iç sınıf olmaz.

class car{
    class wheel{

    }
}

Dört tür iç sınıf vardır.

  1. normal iç sınıf
  2. Yöntem Yerel İç sınıf
  3. İsimsiz iç sınıf
  4. statik iç sınıf

nokta ---

  1. statik iç sınıftan, sadece dış sınıfın statik üyesine erişebiliriz.
  2. İç sınıfın içinde statik üye beyan edemeyiz.
  3. dış sınıfın statik alanında normal iç sınıfı çağırmak.

    Outer 0=new Outer(); Outer.Inner i= O.new Inner();

  4. dış sınıf alanında normal iç sınıfı çağırmak.

    Inner i=new Inner();

  5. dış sınıfın dışında normal iç sınıfı çağırmak.

    Outer 0=new Outer(); Outer.Inner i= O.new Inner();

  6. İç sınıf İç sınıfa giden bu işaretçi.

    this.member-current inner class outerclassname.this--outer class

  7. iç sınıf için uygulanabilir değiştirici - genel, varsayılan,

    final,abstract,strictfp,+private,protected,static

  8. dış $ iç iç sınıf adının adıdır.

  9. iç sınıfın içinde örnek yöntemi sonra dış sınıfın statik ve örnek alanına erişebiliriz.

10. statik sınıf içinde iç sınıf sonra biz sadece statik alana erişebilirsiniz

dış sınıf.

class outer{

    int x=10;
    static int y-20;

    public void m1() {
        int i=30;
        final j=40;

        class inner{

            public void m2() {
                // have accees x,y and j
            }
        }
    }
}
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.