Eğitim Portalı/Java/İç Sınıflar (Inner Classes)
Java01-java/37-ic-siniflar

İç Sınıflar (Inner Classes)

Java'da bir sınıfın içine başka bir sınıf yerleştirebilirsin. Bu iç sınıflar (nested classes), yalnızca bir yerde kullanılan yardımcı yapıları, ait oldukları sınıfın yanında tutmanı sağlar — kod hem düzenli hem de kap…

İç Sınıflar (Inner Classes)

Java'da bir sınıfın içine başka bir sınıf yerleştirebilirsin. Bu iç sınıflar (nested classes), yalnızca bir yerde kullanılan yardımcı yapıları, ait oldukları sınıfın yanında tutmanı sağlar — kod hem düzenli hem de kapsüllenmiş olur. İç sınıfların dört türü vardır; her birinin kendine özgü kuralları ve kullanım yeri vardır.

Dört tür

  1. Üye (member) iç sınıfstatic olmayan, dış nesneye bağlı.
  2. Static nested sınıfstatic, dış nesneye bağlı değil.
  3. Yerel (local) sınıf — bir metodun içinde tanımlı.
  4. Anonim (anonymous) sınıf — isimsiz, anında tanımlanan (ayrı bir konu).

1) Üye iç sınıf

Dış nesnenin bir parçasıdır ve onun (private dahil) üyelerine doğrudan erişir. Her üye iç nesnenin, gizli bir "dış nesne" referansı vardır; bu yüzden oluşturmak için önce bir dış nesne gerekir:

Banka banka = new Banka("Ziraat");
Banka.Hesap hesap = banka.new Hesap(...);   // disNesne.new Ic(...)

Örnek 1 (./Ornek1.java): Bir Banka içindeki Hesap iç sınıfı, dış nesnenin private bankaAdi alanına erişir. Bu tür sınıflar, dış sınıfın iç durumuyla sıkı çalışan yardımcılar (ör. bir koleksiyonun Iterator'ı) için idealdir.

2) Static nested sınıf

static olduğundan dış nesneye bağlı değildir; doğrudan Dis.StatikIc ile oluşturulur. Dış sınıfın yalnızca static üyelerine erişebilir. En yaygın kullanımı Builder ve yardımcı veri yapılarıdır:

Mesaj m = new Mesaj.Builder().kime("...").konu("...").build();

Örnek 2 (./Ornek2.java) bir static nested Builder ve sade bir static nested sınıf gösterir.

İpucu: Bir iç sınıfın dış nesneye ihtiyacı yoksa onu static yap. Aksi halde her iç nesne gereksiz yere bir dış-nesne referansı taşır (ve bellek sızıntısına yol açabilir).

3) Yerel (local) sınıf

Bir metodun (veya bloğun) içinde tanımlanır ve yalnızca orada görünür. Metodun effectively final yerel değişkenlerine erişebilir:

void m() {
    String onek = "[LOG] ";
    class Loglayici { void log(String s) { System.out.println(onek + s); } }
    new Loglayici().log("...");
}

Çok dar kapsamlı, tek seferlik yardımcılar içindir. Örnek 2 bunu da gösterir. Pratikte yerel sınıf yerine genelde daha kısa olan lambda veya anonim sınıf tercih edilir.

4) Anonim sınıf

İsmi olmayan, bir arayüzü/abstract sınıfı anında uygulayan iç sınıftır. Tek seferlik uygulamalar için kullanılır ve genelde lambda'ya dönüşür. Bu, kendi başına bir konudur (bir sonraki bölüm).

Ne zaman hangisi?

TürDış nesne gerekir mi?Kullanım
Üye iç sınıfEvetDış durumla sıkı çalışan yardımcı (Iterator)
Static nestedHayırBuilder, yardımcı veri yapısı
Yerel sınıf(metoda göre)Tek metotta kullanılan dar yardımcı
Anonim sınıf(duruma göre)Tek seferlik arayüz uygulaması (genelde lambda)

Özet

İç sınıfların dört türünü öğrendik: dış nesneye bağlı üye iç sınıf (Örnek 1), bağımsız static nested sınıf (Builder; Örnek 2) ve metot-içi yerel sınıf. "Dış nesne gerekmiyorsa static yap" kuralı önemlidir. İç sınıflar, ilgili yardımcı yapıları ait oldukları yerde, kapsüllü tutmanı sağlar. Sırada, iç sınıfların en kısa ve en sık kullanılan biçimi: anonim sınıflar.

Kod Örnekleri(2)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: Üye (member) iç sınıf — dış nesnenin parçasıdır, dış alanlara erişir.
2// Çalıştırma: java Ornek1.java
3public class Ornek1 {
4
5    public static void main(String[] args) {
6        Banka banka = new Banka("Ziraat");
7        // Üye iç sınıf, DIŞ nesneye bağlıdır: önce dış nesne, sonra .new ile iç nesne.
8        Banka.Hesap hesap = banka.new Hesap("Ada", 1000);
9        hesap.bilgiYaz();   // iç sınıf, dış nesnenin alanına (bankaAdi) erişebilir
10        hesap.paraYatir(500);
11        hesap.bilgiYaz();
12
13        System.out.println("""
14
15                --- Üye (member) iç sınıf ---
16                Bir dış nesnenin İÇİNDE, ona bağlı olarak yaşar; dış nesnenin (private dahil) üyelerine erişir.
17                Oluşturma: disNesne.new Ic(...). Her iç nesnenin gizli bir 'dış nesne' referansı vardır.
18                Kullanım: dış sınıfın iç durumuyla sıkı çalışan yardımcı yapılar (ör. iterator).""");
19    }
20}
21
22class Banka {
23    private final String bankaAdi;
24    Banka(String bankaAdi) { this.bankaAdi = bankaAdi; }
25
26    // Üye (non-static) iç sınıf: dış nesneye bağlı.
27    class Hesap {
28        private final String sahip;
29        private double bakiye;
30        Hesap(String sahip, double bakiye) { this.sahip = sahip; this.bakiye = bakiye; }
31
32        void paraYatir(double t) { bakiye += t; }
33
34        void bilgiYaz() {
35            // bankaAdi DIŞ sınıfın private alanı; iç sınıf doğrudan erişebilir.
36            System.out.println(bankaAdi + " | " + sahip + " | bakiye: " + bakiye);
37        }
38    }
39}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: Static nested (statik iç) sınıf ve yerel (local) sınıf.
2// Çalıştırma: java Ornek2.java
3public class Ornek2 {
4
5    public static void main(String[] args) {
6        // Static nested sınıf: DIŞ nesne GEREKMEZ; doğrudan oluşturulur.
7        Dis.StatikIc s = new Dis.StatikIc("statik iç");
8        s.yaz();
9
10        // Builder deseni genelde static nested sınıfla kurulur:
11        Mesaj m = new Mesaj.Builder().kime("ada@site.com").konu("Selam").build();
12        System.out.println(m);
13
14        // Yerel (local) sınıf: bir METODUN içinde tanımlanır, yalnızca orada görünür.
15        System.out.println("\nYerel sınıf:");
16        yerelSinifOrnegi();
17    }
18
19    static void yerelSinifOrnegi() {
20        String onek = "[LOG] "; // yerel sınıf, metodun (effectively final) değişkenlerine erişir
21        class Loglayici {
22            void log(String mesaj) { System.out.println(onek + mesaj); }
23        }
24        Loglayici l = new Loglayici();
25        l.log("yerel sınıf çalıştı");
26    }
27}
28
29class Dis {
30    static class StatikIc {        // static nested: dış nesneye bağlı DEĞİL
31        private final String ad;
32        StatikIc(String ad) { this.ad = ad; }
33        void yaz() { System.out.println("StatikIc: " + ad); }
34    }
35}
36
37class Mesaj {
38    private final String kime, konu;
39    private Mesaj(Builder b) { this.kime = b.kime; this.konu = b.konu; }
40    @Override public String toString() { return "Mesaj{kime=" + kime + ", konu=" + konu + "}"; }
41
42    // Static nested Builder — dış sınıfın bir örneğine ihtiyaç duymadan çalışır.
43    static class Builder {
44        private String kime = "", konu = "";
45        Builder kime(String k) { this.kime = k; return this; }
46        Builder konu(String k) { this.konu = k; return this; }
47        Mesaj build() { return new Mesaj(this); }
48    }
49}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.