← Kursa Dön
📄 Text · 12 min

Inner Class ve Enum

Giriş

Java'da sınıflar her zaman ayrı dosyalarda yaşamaz. Bazen bir sınıf başka bir sınıfın içinde tanımlanır — buna inner class denir. Ayrıca sabit değer kümeleri için kullanılan enum tipi var. Bu derste ikisini de öğreneceğiz.

Inner Class Nedir?

Bir sınıfın içinde tanımlanan başka bir sınıf. Bunu bir kutu içinde kutu gibi düşün. Dış kutu (outer class) bir bütün, iç kutu (inner class) onun parçası.

class DiskKutu {          // outer class

    class Cikolata {      // inner class
        String tat;
    }
}

Neden inner class kullanırız?

  • İki sınıf mantıksal olarak çok sıkı bağlıysa

  • İç sınıf dış sınıfın private üyelerine erişmek istiyorsa

  • Kodu organize etmek için (dışarıya gereksiz sınıf göstermemek)

Java'da 4 tür inner class var. Sırayla görelim.

1. Non-static Inner Class (Üye İç Sınıf)

En temel inner class. Dış sınıfın bir üyesi gibi davranır.

class Araba {
    private String marka;
    private int hiz;

    Araba(String marka) {
        this.marka = marka;
        this.hiz = 0;
    }

    // Inner class
    class Motor {
        private int beygir;

        Motor(int beygir) {
            this.beygir = beygir;
        }

        void bilgi() {
            // Dış sınıfın private field'ına erişebilir!
            System.out.println(marka + " motoru: " + beygir + " HP");
        }
    }
}
Araba araba = new Araba("BMW");
Araba.Motor motor = araba.new Motor(240);  // dikkat: araba.new
motor.bilgi();  // BMW motoru: 240 HP

Özellikler:

  • Dış sınıfın tüm üyelerine erişebilir (private dahil)

  • Bir dış nesne olmadan oluşturulamaz

  • Oluşturma sözdizimi: disNesne.new IcSinif()

2. Static Inner Class (Statik İç Sınıf)

static keyword ile tanımlanır. Dış sınıfın nesnesine ihtiyaç duymaz.

class Universite {
    String ad;
    static int toplamOgrenci;

    // Static inner class
    static class Adres {
        String sehir;
        String ilce;

        Adres(String sehir, String ilce) {
            this.sehir = sehir;
            this.ilce = ilce;
        }

        void yazdir() {
            // static field'a erişebilir
            System.out.println(sehir + "/" + ilce);
            // System.out.println(ad); // HATA! instance field'a erişemez
        }
    }
}
// Dış nesne gerekmez
Universite.Adres adres = new Universite.Adres("Istanbul", "Kadikoy");
adres.yazdir();  // Istanbul/Kadikoy

Non-static vs Static Inner Class

ÖzellikNon-static InnerStatic Inner
Dış nesne gerekli mi?
Dış instance field'a erişim
Dış static field'a erişim
Oluşturmadis.new Ic()new Dis.Ic()

💡 İpucu: Eğer iç sınıf dış sınıfın instance üyelerine erişmiyorsa, static yap. Daha az bellek kullanır ve daha bağımsızdır. Çoğu durumda static inner class daha mantıklıdır.

3. Local Inner Class (Yerel İç Sınıf)

Metot içinde tanımlanan sınıf. Çok nadir kullanılır.

class Hesaplama {
    void hesapla() {
        // Metot içinde tanımlanmış sınıf
        class Sonuc {
            int deger;
            Sonuc(int deger) { this.deger = deger; }
            void yazdir() { System.out.println("Sonuç: " + deger); }
        }

        Sonuc s = new Sonuc(42);
        s.yazdir();
    }
}

Bu sınıf sadece hesapla() metodu içinde kullanılabilir. Pratikte çok nadir karşılaşırsın, ama sınavlarda sorulabilir.

4. Anonymous Class (Anonim Sınıf)

İsmi olmayan, tek kullanımlık sınıf. Genellikle bir arayüzü (interface) veya sınıfı hızlıca implement etmek için kullanılır.

class Selamlayici {
    void selamla() {
        System.out.println("Merhaba!");
    }
}

public class Main {
    public static void main(String[] args) {
        // Normal yol
        Selamlayici s1 = new Selamlayici();
        s1.selamla();  // Merhaba!

        // Anonymous class — metodu override ediyoruz
        Selamlayici s2 = new Selamlayici() {
            @Override
            void selamla() {
                System.out.println("Selam dostum!");
            }
        };
        s2.selamla();  // Selam dostum!
    }
}

new Selamlayici() { ... } — bu, Selamlayici'nın anonim alt sınıfını oluşturuyor ve anında metodu override ediyor.

Anonymous Class ile Sıralama

En yaygın kullanımı budur (ileride Lambda ile daha kısa yazacaksın):

ArrayList<String> isimler = new ArrayList<>(Arrays.asList("Zeynep", "Ali", "Mehmet"));

Collections.sort(isimler, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.length() - b.length();  // uzunluğa göre sırala
    }
});

System.out.println(isimler);  // [Ali, Zeynep, Mehmet]

Anonymous class'lar Java 8'den önce çok kullanılırdı. Artık Lambda ile çoğu yerde gereksiz oldu, ama hâlâ karşına çıkar.

Enum Nedir?

Enum (enumeration), sabit değerler kümesi tanımlamak için kullanılan özel bir tiptir.

Haftanın günlerini düşün. 7 tane var, hiç değişmiyor. Bunları String ile tutabilirsin: "PAZARTESI", "SALI"... Ama birisi yanlışlıkla "PAZRTESI" yazabilir ve Java bunu yakalayamaz.

Enum ile bu sorun ortadan kalkar:

enum Gun {
    PAZARTESI, SALI, CARSAMBA, PERSEMBE, CUMA, CUMARTESI, PAZAR
}
Gun bugun = Gun.CUMA;
System.out.println(bugun);  // CUMA

// Gun bugun = Gun.PAZRTESI;  // DERLEME HATASI! Böyle bir değer yok

Enum sayesinde tür güvenliği sağlanır. Sadece tanımlanan değerler kullanılabilir.

Enum Tanımlama ve Kullanma

enum Renk {
    KIRMIZI, YESIL, MAVI, SARI, BEYAZ, SIYAH
}

enum Mevsim {
    ILKBAHAR, YAZ, SONBAHAR, KIS
}

enum Boyut {
    KUCUK, ORTA, BUYUK, EKSTRA_BUYUK
}
Renk favori = Renk.MAVI;
Mevsim simdi = Mevsim.KIS;

System.out.println(favori);  // MAVI
System.out.println(simdi);   // KIS

Enum ile switch

Enum'lar switch ile mükemmel çalışır:

Gun gun = Gun.CUMARTESI;

switch (gun) {
    case PAZARTESI:
    case SALI:
    case CARSAMBA:
    case PERSEMBE:
    case CUMA:
        System.out.println("İş günü");
        break;
    case CUMARTESI:
    case PAZAR:
        System.out.println("Hafta sonu!");
        break;
}

⚠️ Dikkat: switch içinde Gun.CUMARTESI değil, sadece CUMARTESI yazılır. Türü zaten Gun olduğu biliniyor.

Enum ile if Karşılaştırma

Gun gun = Gun.PAZAR;

if (gun == Gun.PAZAR) {
    System.out.println("Bugün tatil!");
}

Enum'larda == kullanabilirsin. String gibi .equals() gerekmez çünkü enum değerleri singleton'dır — her değerden sadece bir tane var.

Enum Metotları

Her enum'un hazır metotları var:

// values() — tüm değerleri dizi olarak döndürür
Gun[] gunler = Gun.values();
for (Gun g : gunler) {
    System.out.println(g);
}

// ordinal() — sıra numarası (0'dan başlar)
System.out.println(Gun.PAZARTESI.ordinal()); // 0
System.out.println(Gun.CUMA.ordinal());      // 4

// name() — String olarak adı
System.out.println(Gun.CUMA.name());  // "CUMA"

// valueOf() — String'den enum'a dönüştür
Gun gun = Gun.valueOf("SALI");
System.out.println(gun);  // SALI

// Geçersiz değer → IllegalArgumentException
// Gun.valueOf("TATIL");  // HATA!

Enum'a Field ve Metot Ekleme

Enum sadece basit sabitler değil — içine field, constructor ve metot eklenebilir.

enum Gezegen {
    MERKUR(3.303e+23, 2.4397e6),
    VENUS(4.869e+24, 6.0518e6),
    DUNYA(5.976e+24, 6.37814e6),
    MARS(6.421e+23, 3.3972e6);

    private final double kutle;    // kg
    private final double yaricap;  // metre

    // Enum constructor — her zaman private
    Gezegen(double kutle, double yaricap) {
        this.kutle = kutle;
        this.yaricap = yaricap;
    }

    double getKutle() { return kutle; }
    double getYaricap() { return yaricap; }

    // Yüzey yerçekimi hesabı
    double yuzeyYercekimi() {
        final double G = 6.67300E-11;
        return G * kutle / (yaricap * yaricap);
    }
}
for (Gezegen g : Gezegen.values()) {
    System.out.printf("%s: yerçekimi = %.2f m/s²%n",
        g, g.yuzeyYercekimi());
}

⚠️ Dikkat: Enum constructor her zaman private'tır (yazmasanız bile). Dışarıdan new Gezegen(...) yapılamaz — enum değerleri sadece enum bloğu içinde tanımlanır.

Daha Basit Bir Örnek

enum Boyut {
    KUCUK("S", 29.99),
    ORTA("M", 39.99),
    BUYUK("L", 49.99),
    EKSTRA_BUYUK("XL", 59.99);

    private final String kisaltma;
    private final double fiyat;

    Boyut(String kisaltma, double fiyat) {
        this.kisaltma = kisaltma;
        this.fiyat = fiyat;
    }

    public String getKisaltma() { return kisaltma; }
    public double getFiyat() { return fiyat; }
}
Boyut secim = Boyut.ORTA;
System.out.println(secim.getKisaltma());  // M
System.out.println(secim.getFiyat());     // 39.99

Enum Ne Zaman Kullanılır?

  • Sabit değer kümeleri: Günler, mevsimler, renkler, yönler

  • Durum (state): AKTIF, PASIF, BEKLEMEDE

  • Tip güvenliği: String yerine enum kullanarak yazım hatalarını önle

  • switch ile çalışma: Belirlı durumları kontrol et

// KÖTÜ — String ile
String durum = "aktf";  // yazım hatası, Java yakalaYAMAZ

// İYİ — Enum ile
enum Durum { AKTIF, PASIF, BEKLEMEDE }
Durum durum = Durum.AKTIF;  // yazım hatası → derleme hatası

Pratik Örnek: Sipariş Durumu

enum SiparisDurum {
    OLUSTURULDU("Sipariş oluşturuldu"),
    HAZIRLANIYOR("Sipariş hazırlanıyor"),
    KARGODA("Kargoya verildi"),
    TESLIM_EDILDI("Teslim edildi"),
    IPTAL("İptal edildi");

    private final String aciklama;

    SiparisDurum(String aciklama) {
        this.aciklama = aciklama;
    }

    public String getAciklama() { return aciklama; }

    public boolean iptalEdilebilirMi() {
        return this == OLUSTURULDU || this == HAZIRLANIYOR;
    }
}
SiparisDurum durum = SiparisDurum.KARGODA;

System.out.println(durum.getAciklama());       // Kargoya verildi
System.out.println(durum.iptalEdilebilirMi());  // false

SiparisDurum yeni = SiparisDurum.OLUSTURULDU;
System.out.println(yeni.iptalEdilebilirMi());   // true

Inner Class ve Enum Birlikte

Enum aslında özel bir inner class gibi de kullanılabilir:

class Oyun {
    enum Zorluk {
        KOLAY, ORTA, ZOR
    }

    private Zorluk zorluk;
    private int skor;

    Oyun(Zorluk zorluk) {
        this.zorluk = zorluk;
        this.skor = 0;
    }

    void puanKazan() {
        switch (zorluk) {
            case KOLAY: skor += 10; break;
            case ORTA: skor += 25; break;
            case ZOR: skor += 50; break;
        }
        System.out.println("Skor: " + skor);
    }
}
Oyun oyun = new Oyun(Oyun.Zorluk.ZOR);
oyun.puanKazan();  // Skor: 50
oyun.puanKazan();  // Skor: 100

Özet

  • Inner class başka bir sınıfın içinde tanımlanan sınıftır; dış sınıfın private üyelerine erişebilir

  • Static inner class dış nesneye ihtiyaç duymaz; iç sınıf dış instance'a erişmiyorsa static yap

  • Anonymous class ismi olmayan, tek kullanımlık sınıftır; genellikle interface implement etmek için

  • Enum sabit değer kümeleri tanımlar; tür güvenliği sağlar, switch ile mükemmel çalışır

  • Enum'a field, constructor ve metot eklenebilir; constructor her zaman private'tır

  • Enum kullan: günler, mevsimler, durumlar, tipler gibi sabit kümelerde