Eğitim Portalı/Java/Başlatma Blokları (Initializer Blocks)
Java01-java/41-baslatma-bloklari

Başlatma Blokları (Initializer Blocks)

Bir nesne new ile oluşturulurken veya bir sınıf ilk kez yüklenirken, alanların belirli değerlerle hazırlanması gerekir. Çoğu zaman bunu constructor'da veya alan tanımında yaparız. Ama Java iki ek araç sunar: örnek baş…

Başlatma Blokları (Initializer Blocks)

Bir nesne new ile oluşturulurken veya bir sınıf ilk kez yüklenirken, alanların belirli değerlerle hazırlanması gerekir. Çoğu zaman bunu constructor'da veya alan tanımında yaparız. Ama Java iki ek araç sunar: örnek başlatma bloğu (instance initializer block) ve statik başlatma bloğu (static initializer block). Bunlar, basit atamalarla yapılamayan başlatma mantığını temiz bir şekilde toplamayı sağlar. Bu konu aynı zamanda "nesne kurulurken kod hangi sırayla çalışır?" sorusunu netleştirir.

Instance initializer block

Süslü parantezler içinde, herhangi bir metot dışında yazılan koddur ({ ... }). Her new'de, constructor gövdesinden önce çalışır:

class Urun {
    private int x;
    { x = hesapla(); System.out.println("instance blok"); } // her new'de
    Urun() { System.out.println("constructor"); }
}

Ne işe yarar? Birden çok constructor'ın paylaştığı başlatma kodunu tek yerde toplamak. Üç farklı constructor'ın hepsinde tekrar edilecek kodu, bir instance bloğa koyarsın; blok hepsinden önce çalışır. Örnek 1 (./Ornek1.java) bunu ve tam başlatma sırasını gösterir.

Static initializer block

static { ... } bloğu, sınıf ilk yüklendiğinde bir kez çalışır (tüm static alanlardan sonra, herhangi bir nesne oluşturulmadan veya static metot çağrılmadan önce). Tek satırda atanamayan karmaşık statik başlatma içindir:

class DovizTablosu {
    private static final Map<String,Double> KURLAR;
    static {                                  // bir kez, sınıf yüklenince
        Map<String,Double> m = new HashMap<>();
        m.put("USD", 32.50); m.put("EUR", 35.10);
        KURLAR = Collections.unmodifiableMap(m);
    }
}

Kullanım: sabit tablolar/haritalar kurmak, yapılandırma/kaynak yüklemek, hesaplanmış sabitler üretmek. Basit atamalar için gerek yoktur (static int X = 5; yeter). Örnek 2 (./Ornek2.java) bir döviz tablosunu static blokta kurar.

Tam başlatma sırası

Bir nesne oluşturulurken kod şu sırayla çalışır:

  1. (Yalnızca ilk kez, sınıf yüklenince) static alan başlatmaları + static bloklar — yazıldıkları sırada, bir kez.
  2. Her new'de:
    • Önce üst sınıf kurulur (super(...)).
    • Sonra instance alan başlatmaları + instance initializer blokları, kodda yazıldıkları sırayla.
    • En son constructor gövdesi.
[static blok]      <- ilk new'den önce, bir kez
[instance blok]    <- her new'de, constructor'dan önce
[constructor]      <- en son

Örnek 1 iki nesne oluşturarak static bloğun bir kez, instance bloğun ise her seferinde çalıştığını kanıtlar.

Ne zaman kullanmalı, ne zaman kaçınmalı?

  • Static blok: Karmaşık statik veri kurulumu için iyi. Alternatif: statik bir fabrika metodu. Static blokta atılan exception'lar ExceptionInInitializerError'a yol açar ve sınıf yüklenemez; dikkatli ol.
  • Instance blok: Constructor'lar arası paylaşılan kod için kullanışlı; ancak çoğu durumda ortak bir private başlatma metodu veya constructor zincirleme (this(...)) daha okunaklı olabilir. Record'larda instance initializer block kullanılamaz (compact constructor kullan).

Özet

İki başlatma bloğunu öğrendik: her new'de constructor'dan önce çalışan ve constructor'lar arası ortak kodu toplayan instance initializer block (Örnek 1) ve sınıf yüklenince bir kez çalışıp karmaşık statik kurulum yapan static initializer block (Örnek 2). Ayrıca nesne kurulumunun tam sırasını (static → instance blok → constructor) netleştirdik. Bu, OOP eksik konuları bölümünü tamamlıyor.

Kod Örnekleri(2)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: Instance initializer block (örnek başlatma bloğu) ve çalışma sırası.
2// Çalıştırma: java Ornek1.java
3public class Ornek1 {
4
5    public static void main(String[] args) {
6        System.out.println(">> İlk nesne oluşturuluyor:");
7        new Urun("Klavye");
8        System.out.println("\n>> İkinci nesne oluşturuluyor:");
9        new Urun("Mouse");
10
11        System.out.println("""
12
13                --- Başlatma sırası (nesne oluşturulurken) ---
14                1) (yalnızca İLK kez) static alanlar + static bloklar — sınıf yüklenince, BİR KEZ.
15                2) Her 'new'de: üst sınıf kurulur, sonra:
16                   - instance alan başlatmaları + instance initializer blokları (yazıldıkları SIRADA),
17                   - en son CONSTRUCTOR gövdesi.
18                Instance initializer bloğu, birden çok constructor'ın PAYLAŞTIĞI başlatma kodunu
19                tek yerde toplamak için kullanılır (her constructor'dan önce çalışır).""");
20    }
21}
22
23class Urun {
24    // 1) static blok: sınıf ilk yüklendiğinde BİR KEZ çalışır.
25    static int uretilenSayisi;
26    static { uretilenSayisi = 0; System.out.println("  [static blok] Urun sınıfı yüklendi"); }
27
28    // 2) instance alan başlatma + instance initializer blok: HER new'de, constructor'dan ÖNCE.
29    private final String ad;
30    private final long olusturmaZamani = System.nanoTime();
31    { // instance initializer block
32        uretilenSayisi++;
33        System.out.println("  [instance blok] sayac=" + uretilenSayisi);
34    }
35
36    // 3) constructor: en son çalışır.
37    Urun(String ad) {
38        this.ad = ad;
39        System.out.println("  [constructor] ad=" + this.ad + ", zaman kaydı alındı=" + (olusturmaZamani > 0));
40    }
41}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: Static initializer block — sınıf düzeyinde tek seferlik, karmaşık başlatma.
2// Çalıştırma: java Ornek2.java
3import java.util.Map;
4import java.util.HashMap;
5import java.util.Collections;
6
7public class Ornek2 {
8
9    public static void main(String[] args) {
10        // Statik tablo, sınıf yüklenince static blokta bir kez kurulmuştu.
11        System.out.println("USD kuru: " + DovizTablosu.kur("USD"));
12        System.out.println("EUR kuru: " + DovizTablosu.kur("EUR"));
13        System.out.println("Bilinmeyen: " + DovizTablosu.kur("XXX"));
14        System.out.println("Toplam para birimi: " + DovizTablosu.adet());
15
16        System.out.println("""
17
18                --- static initializer block ---
19                static { ... } bloğu, sınıf İLK yüklendiğinde BİR KEZ çalışır (tüm static alanlardan sonra,
20                herhangi bir nesne/static metot kullanılmadan önce).
21                Kullanım: tek satırda atanamayan KARMAŞIK statik başlatma — sabit tablolar/haritalar kurmak,
22                kaynak/yapılandırma yüklemek, hesaplanmış sabitler üretmek.
23                Basit atamalar için static blok gerekmez (alan başlatması yeter): static int X = 5;""");
24    }
25}
26
27class DovizTablosu {
28    private static final Map<String, Double> KURLAR;
29
30    // Karmaşık başlatma: bir Map'i doldurup değiştirilemez yap. Tek satıra sığmaz -> static blok.
31    static {
32        Map<String, Double> m = new HashMap<>();
33        m.put("USD", 32.50);
34        m.put("EUR", 35.10);
35        m.put("GBP", 41.20);
36        KURLAR = Collections.unmodifiableMap(m);
37        System.out.println("[static blok] döviz tablosu yüklendi (" + m.size() + " kayıt)");
38    }
39
40    static double kur(String kod) { return KURLAR.getOrDefault(kod, 0.0); }
41    static int adet() { return KURLAR.size(); }
42}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.