---
title: 'Nesne ve Tablo Bağlaması'
source: 'https://academia.sh/tr/kurslar/kurumsal-uygulama-cercevesi/nesne-ve-tablo-baglamasi'
course: 'Kurumsal Uygulama Çerçevesi'
language: tr
updated: '2026-08-23T14:25:05+00:00'
license: 'CC BY-SA 4.0'
---

# Nesne ve Tablo Bağlaması

Bir varlık nesnesinin dört alanından ikisi yükleme anında, ikisi ilk erişimde yükleniyor. İkinci erişim tabloyu tekrar okumuyor, önbellekten dönüyor; ama nesne kaptan ayrıldıktan sonra hiç erişilmemiş bir alana erişildiğinde tablo okunamıyor ve kusur sessizce boş bir değer olarak dönüyor.

Önceki ders bir arayüzün arkasında hangi gerçekleştirimin durduğunu ölçtü, ama gerçekleştirimin
kendi alanlarının nesne ile depo arasında nasıl eşleştiği hiç sorulmadı. Bu ders bunu ele
alıyor: bir nesnenin alanları ile bir tablonun sütunları arasındaki bağlamanın kaynakta bir
açıklamadan geldiğini, ve erişilmeyen bir alanın hiç yüklenmediğini ölçüyor. Kursun terim
kararında bu bağlantı **nesne–tablo bağlaması**dır; nesnenin kendisi ise bir **varlık
nesnesi**.

Tablo burada da **modellenir**: gerçek bir veritabanı bağlantısı açılmaz, gerçek bir sorgu
çalıştırılmaz. Bir "tablo", satır kimliğine göre erişilen bir sütun adı–değer yapısından
ibaret — `Map<Integer, Map<String, Object>>`. Bir varlık nesnesi bu satırlardan biriyle
bağlanır, ve nesnenin hangi alanının hangi sütuna karşılık geldiği kaynakta iki açıklamayla
belirtiliyor:
`@Sutun` her zaman yüklenen alanlar için, `@TembelSutun` yalnız erişildiğinde yüklenen alanlar
için.

Bu ayrımın bir maliyet sorusu olduğu unutulmamalı. Gerçek bir depoda her sütun bir disk
erişimi, bir ağ gecikmesi taşıyabilir; bir satırın yalnız iki sütununu her zaman okuyup
kalanını yalnız gerektiğinde okumak, bir nesnenin **hiç kullanılmayacak** alanları için hiç
ödeme yapmamak anlamına gelir. Bu derste maliyetin kendisi ölçülmüyor — süre ve gecikme
yazılmıyor — ama maliyetin **nereye düştüğü** ölçülüyor: `yukSirasi` listesi, hangi sütunun
ne zaman okunduğunu tutan bir günlük, ve bu günlük hem yükleme anındaki hem erişim anındaki
her okumayı aynı biçimde kaydediyor.

## Yükleme Anında İki Alan, Erişimde İki Alan

- **WV20.** `UrunKarti` dört alan taşıyor: `ad` ve `miktar` `@Sutun`, `aciklamaOnbellek` ve
  `resimYoluOnbellek` `@TembelSutun`. Alan adları sütun adlarıyla birebir aynı olmak
  zorunda değil; açıklamanın `ad` parametresi eşleşmeyi kaynaktaki alan adından bağımsız
  kılıyor.
- **WV21.** Tembel alanların gerçek değeri bir "önbellek" alanında tutuluyor; ilk kez `null`
  olan bu alan, ilk başarılı yüklemeden sonra bir daha hiç sıfırlanmıyor.

`Kap.yukle` bir satırı bir nesneye dönüştürürken yalnız `@Sutun` taşıyan alanları dolduruyor;
`@TembelSutun` taşıyanlara hiç dokunmuyor. Nesne, hangi kaba ve hangi satıra ait olduğunu
`VarlikNesnesi` üst sınıfından gelen `oturum` ve `satirId` alanlarıyla taşıyor — bu ikisi
`@Sutun` değil, nesne kabının kendi kurduğu bir bağ.

```java
// Kap.java — nesne-tablo baglamasi aciklamadan doguyor, tembel alan erisim aninda yukleniyor
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;

public class Kap {

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE)
    @interface Tablo { String ad(); }

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD)
    @interface Sutun { String ad(); }

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD)
    @interface TembelSutun { String ad(); }

    final Map<Integer, Map<String, Object>> tablo = new LinkedHashMap<>();
    final List<String> yukSirasi = new ArrayList<>();

    void satirEkle(int id, Map<String, Object> sutunlar) { tablo.put(id, sutunlar); }

    Object sutunOku(int id, String sutunAdi, String etiket) {
        yukSirasi.add(sutunAdi + ": " + etiket);
        return tablo.get(id).get(sutunAdi);
    }

    <T> T yukle(Class<T> tip, int id) throws ReflectiveOperationException {
        T nesne = tip.getDeclaredConstructor().newInstance();
        for (Field f : tip.getDeclaredFields()) {
            f.setAccessible(true);
            Sutun s = f.getAnnotation(Sutun.class);
            if (s != null) f.set(nesne, sutunOku(id, s.ad(), "yukleme-aninda"));
        }
        Field oturumAlani = tip.getSuperclass().getDeclaredField("oturum");
        Field idAlani = tip.getSuperclass().getDeclaredField("satirId");
        oturumAlani.setAccessible(true);
        idAlani.setAccessible(true);
        oturumAlani.set(nesne, this);
        idAlani.set(nesne, id);
        return nesne;
    }

    void ayril(VarlikNesnesi nesne) throws ReflectiveOperationException {
        Field oturumAlani = VarlikNesnesi.class.getDeclaredField("oturum");
        oturumAlani.setAccessible(true);
        oturumAlani.set(nesne, null);
    }

    public static void main(String[] args) throws Exception {
        Kap kap = new Kap();
        kap.satirEkle(1, Map.of("ad", "vida", "miktar", 12, "aciklama", "6mm somunlu vida", "resimYolu", "gorsel/vida.png"));

        System.out.println("-- kap ile yukleme: sadece iki sutun aninda okunuyor --");
        UrunKarti urun = kap.yukle(UrunKarti.class, 1);
        System.out.println("yukleme sonrasi yuk sirasi: " + kap.yukSirasi);
        System.out.println("toplam alan: 4, yukleme aninda okunan: "
                + kap.yukSirasi.stream().filter(s -> s.endsWith("yukleme-aninda")).count());

        System.out.println("-- tembel alana erisim: ilk cagri tabloyu okuyor --");
        System.out.println("aciklama: " + urun.aciklama());
        System.out.println("aciklama tekrar: " + urun.aciklama());
        System.out.println("yuk sirasi (aciklama sonrasi): " + kap.yukSirasi);
        System.out.println("aciklama icin kac kez tablo okundu: "
                + kap.yukSirasi.stream().filter(s -> s.startsWith("aciklama:") && s.endsWith("erisim-aninda")).count());
        System.out.println("resimYolu hic erisilmedi, kayitta hic gecmiyor: "
                + kap.yukSirasi.stream().noneMatch(s -> s.startsWith("resimYolu")));

        System.out.println("-- kaptan ayrilma sonrasi hic erisilmemis tembel alan --");
        kap.ayril(urun);
        System.out.println("resimYolu (kap ayrildiktan sonra ilk erisim): '" + urun.resimYolu() + "'");
        System.out.println("kusur turu: sessiz (istisna yok, bos deger sessizce dondu)");

        System.out.println("-- elle kurulan nesne: kap hic devrede degil --");
        UrunKarti elleKurulan = new UrunKarti();
        System.out.println("elle kurulan nesnede aciklama ilk erisimde: '" + elleKurulan.aciklama() + "'");
    }
}

class VarlikNesnesi {
    transient Kap oturum;
    transient int satirId;

    Object tembelOku(String sutunAdi, String onbellek) {
        if (onbellek != null) return onbellek;
        if (oturum == null) return "";
        return String.valueOf(oturum.sutunOku(satirId, sutunAdi, "erisim-aninda"));
    }
}

@Kap.Tablo(ad = "urun_karti")
class UrunKarti extends VarlikNesnesi {
    @Kap.Sutun(ad = "ad") String ad;
    @Kap.Sutun(ad = "miktar") int miktar;
    @Kap.TembelSutun(ad = "aciklama") String aciklamaOnbellek;
    @Kap.TembelSutun(ad = "resimYolu") String resimYoluOnbellek;

    String aciklama() {
        aciklamaOnbellek = (String) tembelOku("aciklama", aciklamaOnbellek);
        return aciklamaOnbellek;
    }

    String resimYolu() {
        resimYoluOnbellek = (String) tembelOku("resimYolu", resimYoluOnbellek);
        return resimYoluOnbellek;
    }
}
```

```
-- kap ile yukleme: sadece iki sutun aninda okunuyor --
yukleme sonrasi yuk sirasi: [ad: yukleme-aninda, miktar: yukleme-aninda]
toplam alan: 4, yukleme aninda okunan: 2
-- tembel alana erisim: ilk cagri tabloyu okuyor --
aciklama: 6mm somunlu vida
aciklama tekrar: 6mm somunlu vida
yuk sirasi (aciklama sonrasi): [ad: yukleme-aninda, miktar: yukleme-aninda, aciklama: erisim-aninda]
aciklama icin kac kez tablo okundu: 1
resimYolu hic erisilmedi, kayitta hic gecmiyor: true
-- kaptan ayrilma sonrasi hic erisilmemis tembel alan --
resimYolu (kap ayrildiktan sonra ilk erisim): ''
kusur turu: sessiz (istisna yok, bos deger sessizce dondu)
-- elle kurulan nesne: kap hic devrede degil --
elle kurulan nesnede aciklama ilk erisimde: ''
```

`urun.yukSirasi`'nin ilk hâli yalnız iki girdi taşıyor: `ad` ve `miktar`. `aciklama` ile
`resimYolu` bu listede hiç görünmüyor, çünkü `yukle` onları hiç okumadı — dört alanlı bir
nesne, tablonun yalnız iki sütununu okuyarak kuruldu. Bu, kaynak metinle çelişen bir sonuç
değil, kaynağın **tam olarak söylediği** şey: `@Sutun` yalnız iki alanda var, `@TembelSutun`
diğer ikisinde, ve `yukle` yalnız `@Sutun` taşıyanları dolduruyor. Ama satırı okuyan biri
`UrunKarti`'nin dört alanının da bir tablo satırından geldiğini bilir; hangi ikisinin **ne
zaman** geldiğini bilmek için `Kap.yukle` yönteminin gövdesini okumak gerekiyor.

## Tembel Alan Yalnız Bir Kez Yükleniyor

- **WV22.** `aciklama()` yöntemi çağrıldığında önce kendi önbellek alanına bakıyor; alan
  doluysa tabloya hiç gitmiyor. Bu, yöntemin adının "tembel" olmasının ikinci anlamı: yalnız
  ilk erişimde değil, en fazla **bir kez** yükleniyor.

`aciklama()` iki kez çağrılıyor ve `yuk sirasi` listesine yalnız bir `"aciklama:
erisim-aninda"` girdisi ekleniyor. İlk çağrı `aciklamaOnbellek` alanının `null` olduğunu
görüyor, tabloyu okuyor, sonucu aynı alana yazıyor. İkinci çağrı aynı alanın artık dolu
olduğunu görüyor ve tabloya hiç gitmiyor. Bu, kap içindeki tekil kapsamla aynı aileden bir
davranış — orada bir bileşenin ikinci isteği aynı örneği döndürüyordu, burada bir alanın
ikinci erişimi aynı değeri döndürüyor — ama kaynağı farklı: tekillik kabın kendi kural
tablosundaydı, burada önbellekleme `tembelOku` yönteminin kendi gövdesinde yazılı bir kontrol.
`resimYolu` alanına hiç erişilmediği için `yuk sirasi` listesinde bu sütun için hiçbir girdi
yok — dört alanlı nesnenin dördüncü alanı, program sonuna kadar tabloya hiç sorulmadan
kalabiliyor. Bu, tembel yüklemenin asıl kazancı: bir nesnenin bütün alanlarını taşıması,
hepsinin gerçekten okunacağı anlamına gelmiyor, ve okunmayan alan için hiçbir maliyet
ödenmiyor.

Önbellekleme yalnız bir performans kararı değil, bir tutarlılık kararı da taşıyor. Tabloya
`aciklama()` çağrısı arasında başka bir yol aynı satırın `aciklama` sütununu değiştirseydi,
`urun` nesnesi bunu asla görmezdi — önbellek dolduktan sonra `tembelOku` bir daha tabloya
hiç bakmıyor. Bu ders bu senaryoyu koşturmuyor, ama sonucu kaynaktan çıkarılabilir: bir
tembel alan yalnız **ilk okunduğu anki** değeri taşıyor, o andan sonra tablo değişse de nesne
değişmiyor. Bir varlık nesnesini uzun süre elde tutan bir çağıran için bu, yükleme anının
gerçek bir anlık görüntü olduğu, ve o görüntünün süresiz doğru kalacağının hiçbir yerde
vaat edilmediği anlamına geliyor.

## Kap Dışında Tembel Yükleme Çalışmıyor: Sessiz Bir Boşluk

- **WV23.** `ayril` yalnız `oturum` alanını `null` yapıyor; nesnenin diğer alanları,
  önbelleğe alınmış olan `ad` ve `miktar` dahil, hiç değişmiyor.
- **WV24.** `tembelOku`, `oturum == null` gördüğünde bir istisna fırlatmak yerine boş bir
  dizge döndürüyor. Bu, dersin ikinci sessiz kusuru: erişim başarısız olmuyor, yalnız
  yanlış bir değer üretiyor.

`kap.ayril(urun)` çağrısı, `urun`'un kabın oturumuyla bağını kesiyor — gerçek bir uygulamada
bu, bir isteğin işlenmesi bittikten sonra nesnenin kap dışına, örneğin bir başka katmana
taşınmasının karşılığı. Bu noktaya kadar `resimYolu` hiç erişilmemişti; `ayril`'dan sonra ilk
kez çağrıldığında `tembelOku` artık `oturum`'un `null` olduğunu görüyor ve tabloya
sorabileceği hiçbir yol kalmıyor. Yöntem bir istisna fırlatmak yerine boş bir dizge
döndürüyor, ve çağıran taraf bu boş dizgeyi gerçek bir "resim yolu yok" durumundan ayırt
edemiyor. Kusur burada da **sessiz**: program çökmüyor, hiçbir uyarı basmıyor, yalnız yanlış
bir değerle devam ediyor.

Bu, dersin sınırlayıcı ölçümü: **tembel yükleme kabın dışında çalışmaz; nesne kaptan
çıktıktan sonra erişilen alan boş kalır.** `ad` ve `miktar` bu sorunu yaşamıyor, çünkü ikisi
de yükleme anında dolduruldu ve `ayril`'dan etkilenmiyor — sorun yalnız **hiç erişilmemiş**
tembel alanlarda ortaya çıkıyor. Bu da yükleme stratejisinin gizli bir kuralını gösteriyor:
bir varlık nesnesinin kap içinde ne kadar süre kaldığı, hangi tembel alanlarına erişildiğini
belirliyor, ve erişim penceresi kapandıktan sonra erişilmemiş kalan her tembel alan bir daha
asla doğru değerine ulaşamıyor.

Son ölçüm bu kuralı en baştan kuran bir nesneyle sınıyor: `new UrunKarti()` ile elle kurulan
nesnenin `oturum` alanı hiçbir zaman bir kaba bağlanmadı, baştan `null`. Bu nesnede
`aciklama()` çağrıldığında sonuç yine boş dizge — `ayril` çağrılan nesneyle birebir aynı
davranış, aynı sessiz sonuç. İki yol da aynı noktaya çıkıyor: nesne kabın oturumuyla ya hiç
bağlanmadı ya da bağı sonradan koptu, ve her iki durumda da tembel alan erişimi aynı boş
değerle sonuçlanıyor. `@TembelSutun` açıklaması `UrunKarti` sınıfının üzerinde durmaya devam
ediyor — kaldırılmadı — ama onu yerine getirecek bir oturum yoksa, önceki derslerde görülen
kuralın bir kez daha doğrulanması: açıklama bir istektir, isteği karşılayacak taraf yoksa
hiçbir şey olmaz.

Bu ikisi arasındaki tek fark, kusurun **ne kadar sürpriz** olduğu. Elle kurulan bir nesnede
kap hiç devrede olmadığı zaten baştan belli — bir geliştirici bu nesneyi `new` ile kurarken
tembel yüklemenin çalışmayacağını beklemek zorunda. Ama `ayril`'dan geçen nesne az önce
kabın içindeydi; `ad` ve `miktar` alanları doğru değerlerini taşıyor, nesne her bakımdan
"gerçek" görünüyor. Bu görünüş, `resimYolu` gibi hiç erişilmemiş bir alanın da aynı ölçüde
güvenilir olduğu izlenimini veriyor — oysa o alan, nesnenin görünüşte tamamlanmış olmasına
rağmen hâlâ kabın oturumuna bağımlı. Sınırlayıcı ölçümün asıl değeri burada: sorun rastgele
bir alanda değil, tam olarak **kap dışına en son çıkan** ve **hiç dokunulmamış** alanlarda
ortaya çıkıyor, ve bu ikisinin kesişimi kaynak metinde hiçbir yerde işaretli değil.

## Özet

- `UrunKarti`'nin dört alanından ikisi (`ad`, `miktar`) yükleme anında, ikisi
  (`aciklamaOnbellek`, `resimYoluOnbellek`) yalnız ilk erişimde tablodan okundu.
- Bir tembel alana ikinci erişim tabloya hiç gitmedi; önbellek alanı doluysa `tembelOku`
  doğrudan onu döndürdü.
- Hiç erişilmeyen bir tembel alan (`resimYolu`) programın sonuna kadar tabloya hiç
  sorulmadı; bu, tembel yüklemenin okunmayan alan için maliyet ödetmeyen tarafı.
- Nesne kaptan ayrıldıktan sonra hiç erişilmemiş bir tembel alana erişildiğinde tabloya
  ulaşılamadı ve yöntem istisna yerine boş bir dizge döndürdü; kusur sessiz kaldı.
- Elle kurulan bir nesnede aynı tembel alana erişim, kaptan ayrılan nesneyle birebir aynı
  boş sonucu verdi; ikisinde de eksik olan şey kabın oturumuydu.

## Sonraki Adım

Bu ders bir nesnenin alanlarının ne zaman yüklendiğini ölçtü, ama bu yüklemenin ve
üzerindeki değişikliklerin nerede başlayıp nerede bittiği hiç sorulmadı. Sıradaki ders bunu
ele alıyor: bildirimsel bir işlem sınırının kaynakta bir açıklama olduğunu, ve bir bileşenin
kendi kendini çağırmasının bu sınırı nasıl atladığını ölçüyor.
