---
title: 'Kayıtlar ve Numaralandırmalar'
source: 'https://academia.sh/tr/kurslar/java-nesne-modeli/kayitlar-ve-numaralandirmalar'
course: 'Nesneye Dayalı Java'
language: tr
updated: '2026-08-17T18:09:41+00:00'
license: 'CC BY-SA 4.0'
---

# Kayıtlar ve Numaralandırmalar

Tek satırlık bir kayıt bildirimi sınıf dosyasında on üye üretir ve üretilen sınıf genişletilemez, yani bildirilen tiple çalışma zamanı tipi hiçbir zaman ayrılamaz. Numaralandırmada ise gövde yazılan bir sabit kendi sınıfını alır; kaydın ürettiği eşitlik ise yalnız sığ korur.

Önceki derste derleyici kaynakta hiç yazılmamış sınıflar üretti ve onlara gizli alanlarla
gizli yapıcı parametreleri koydu. Üretilen her şeyin ortak yanı, bir programcının elle
yazacağı bir bağlama işini üstlenmesiydi — ama üretilenler görünmezdi: hiçbiri kaynaktan
çağrılabilecek bir yüzey değildi.

Bu derste aynı üretim yeteneği görünür bir işe koşulur. Java'da bir veri taşıyıcının bütün
yüzeyi — alan okuyucuları, eşitlik, karma değeri ve metne çevirme — tek bir satırdan
üretilebilir; bu satırın adı **kayıt (record)** bildirimidir. Sabit bir kümeyi tanımlayan
**numaralandırma** da benzer bir üretim yapar. Sorular üç tanedir: bir satır kaç üye
üretiyor, üretilen üyeler kararı hangi tarafa bırakıyor, ve üretilen eşitlik nereye kadar
koruyor?

## Ölçüm Çekirdeği

Ölçüm bir kaynağı derler, ürettiği sınıf dosyasındaki alan ve yöntem adlarını okur, sınıfın
genişletilebilir olup olmadığını bildirir ve ayrıca bir kaynağın derlenip derlenmediğini
döndürür.

- **SN36** — Kâhin kaynağın kendisidir: kayıt bildiriminin gövdesi boştur, dolayısıyla sınıf
  dosyasında görünen her üye derleyicinin ürettiğidir.
- **SN37** — Üye listesi sınıf dosyasından okunur; sayım kaynaktaki yazımı değil, üretilen
  dosyayı temel alır.
- **SN38** — Derleme denemeleri kendi geçici dizinlerinde yapılır ve sonuç tek bir çıkış
  koduyla okunur.
- **SN39** — Eşitlik ölçümünde iki nesne ayrı ayrı kurulur; kimlik yalnız `==` ile
  karşılaştırılır ve hiçbir kimlik sayısı basılmaz.
- **SN40** — Karma değeri yalnız iki nesnenin karması **birbirine eşit mi** sorusuyla anılır ve
  bu soru yalnız değer tabanlı karma üreten bileşenler için sorulur.

```java
// Olcek.java — sınıf dosyasındaki üyeler ve genişletme denemesi
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.classfile.*;
import java.lang.reflect.AccessFlag;
import java.nio.file.*;
import java.util.*;
import java.util.spi.ToolProvider;

class Olcek {
    record Sinif(boolean sonlanmis, List<String> alan, List<String> yontem) {}

    static Path yeniDizin() throws Exception { return Files.createTempDirectory("olcek"); }

    static boolean derle(Path d, String ad, String kaynak) throws Exception {
        Path k = d.resolve(ad + ".java");
        Files.writeString(k, kaynak);
        PrintWriter bos = new PrintWriter(Writer.nullWriter());
        return ToolProvider.findFirst("javac").orElseThrow()
                .run(bos, bos, "-d", d.toString(), "-cp", d.toString(), k.toString()) == 0;
    }

    static Sinif oku(String kaynak, String ad) throws Exception {
        Path d = yeniDizin();
        if (!derle(d, ad, kaynak)) throw new IllegalStateException("derlenmedi: " + ad);
        ClassModel cm = ClassFile.of().parse(d.resolve(ad + ".class"));
        List<String> alan = new ArrayList<>();
        for (FieldModel f : cm.fields())
            alan.add(f.fieldName().stringValue()
                    + (f.flags().has(AccessFlag.FINAL) ? " [final]" : ""));
        List<String> yontem = new ArrayList<>();
        for (MethodModel m : cm.methods()) yontem.add(m.methodName().stringValue());
        return new Sinif(cm.flags().has(AccessFlag.FINAL), alan, yontem);
    }
}
```

## Tek Satır, On Üye

Ölçülen kaynak tek bir satırdır ve gövdesi boştur. Kursun somut ekseni burada da sürer: üç
alanlı bir depo kaydı — ad, adet ve gram cinsinden ağırlık.

```java
// Uretilen.java — tek satırlık bir kayıt bildiriminden kaç üye çıkıyor
import java.util.TreeSet;

public class Uretilen {
    static final String ELLE = """
        class Elle {
            private final String ad; private final int adet; private final long agirlik;
            Elle(String ad, int adet, long agirlik) {
                this.ad = ad; this.adet = adet; this.agirlik = agirlik;
            }
            public String ad() { return ad; }
            public int adet() { return adet; }
            public long agirlik() { return agirlik; }
            @Override public boolean equals(Object o) {
                return o instanceof Elle e
                        && ad.equals(e.ad) && adet == e.adet && agirlik == e.agirlik;
            }
            @Override public int hashCode() {
                return java.util.Objects.hash(ad, adet, agirlik);
            }
            @Override public String toString() {
                return "Elle[ad=" + ad + ", adet=" + adet + ", agirlik=" + agirlik + "]";
            }
        }
        """;

    public static void main(String[] args) throws Exception {
        String kaynak = "record Kayit(String ad, int adet, long agirlik) { }";
        Olcek.Sinif k = Olcek.oku(kaynak, "Kayit");
        System.out.println("kaynak: " + kaynak);
        System.out.println("alanlar (" + k.alan().size() + "): " + k.alan());
        System.out.println("yontemler (" + k.yontem().size() + "): " + k.yontem());
        System.out.println("sinif final mi: " + k.sonlanmis());
        System.out.println();
        Olcek.Sinif e = Olcek.oku(ELLE, "Elle");
        System.out.println("kaynak satiri: kayit 1, elle yazilan " + ELLE.strip().lines().count());
        System.out.println("uye sayisi   : kayit " + (k.alan().size() + k.yontem().size())
                + ", elle yazilan " + (e.alan().size() + e.yontem().size()));
        System.out.println("yontem adlari ayni mi: "
                + new TreeSet<>(k.yontem()).equals(new TreeSet<>(e.yontem())));
        System.out.println();
        System.out.printf("%-34s -> derleniyor mu: %s%n", "kaydi genisletme",
                Olcek.derle(Olcek.yeniDizin(), "T", kaynak + " class T extends Kayit { }"));
        System.out.printf("%-34s -> derleniyor mu: %s%n", "kaydin arayuz gerceklestirmesi",
                Olcek.derle(Olcek.yeniDizin(), "T", "interface T { }"
                        + " record Kayit(String ad) implements T { }"));
        System.out.printf("%-34s -> derleniyor mu: %s%n", "alanina yeniden atama",
                Olcek.derle(Olcek.yeniDizin(), "T",
                        "record Kayit(String ad) { } class T { void f(Kayit k) { k.ad = \"x\"; } }"));
    }
}
```

```
kaynak: record Kayit(String ad, int adet, long agirlik) { }
alanlar (3): [ad [final], adet [final], agirlik [final]]
yontemler (7): [<init>, toString, hashCode, equals, ad, adet, agirlik]
sinif final mi: true

kaynak satiri: kayit 1, elle yazilan 19
uye sayisi   : kayit 10, elle yazilan 10
yontem adlari ayni mi: true

kaydi genisletme                   -> derleniyor mu: false
kaydin arayuz gerceklestirmesi     -> derleniyor mu: true
alanina yeniden atama              -> derleniyor mu: false
```

Kaynakta bir bildirim satırı yazıldı; sınıf dosyasında **üç alan** ve **yedi yöntem**, toplam
**on üye** var. Üç alanın üçü de `final` bayrağını taşıyor. Yedi yöntemin üçü **bileşen
okuyucusudur** (`ad`, `adet`, `agirlik`), üçü Java'nın her nesnesinden beklediği yüzeydir
(`toString`, `hashCode`, `equals`) ve biri bileşenleri alan **asıl yapıcıdır**. Bir önceki
dersin gizli alanlarından farkı buradadır: bunlar gizli değildir, çağrılabilir bir yüzeydir.

Ortadaki üç satır bu yüzeyin elle yazıldığında neye mal olduğunu ölçüyor. Aynı on üyeyi elle
kuran sınıf **19 satırdır** ve sınıf dosyasında yine **10 üye** bırakır; iki sınıfın yöntem
adları birebir aynıdır. Kayıt yeni bir düzenek getirmez — sınıf dosyası düzeyinde ortaya çıkan
şey sıradan bir sınıftır. Getirdiği şey, bu on üyenin **elle yazılmasında yapılabilecek
hataların ortadan kalkmasıdır**: bir bileşen eklendiğinde elle yazılan eşitlikte onu unutmak
mümkündür, üretilen eşitlikte değildir.

Java Temelleri kursunda numaralandırma için de aynı ölçüm yapılmış, kaynakta yalnız iki ad
yazılan bir bildirimin sınıf dosyasında kaynakta bulunmayan alanlar ve yöntemler taşıdığı
gösterilmişti. İki biçim aynı düzeneği kullanır; farkları ne ürettikleridir, üretip
üretmedikleri değil.

Alt bölümdeki üç deneme üretilenin bir yanını daha gösteriyor. Kayıt **genişletilemez**:
sınıf `final` bayrağını taşır ve onu genişleten bir sınıf derlenmez. Bir arayüz
gerçekleştirmesi ise serbesttir. Alanına yeniden atama da derlenmez, çünkü alanların hepsi
`final`dır — önceki dersin ölçtüğü kısıt burada kaynakta hiç yazılmadan uygulanır.

## Üretilen Üyeler Kararı Kime Bırakıyor

Kaydın genişletilememesi kursun sorusunu tuhaf bir yere getirir. Bir kayıt tipinin alt tipi
olamayacağına göre, o tiple bildirilmiş bir adın çalışma zamanı tipi her zaman aynı olacaktır.
Öyleyse üretilen üyeler için soru anlamını mı yitirir?

```java
// Taraf.java — üretilen üyeler kararı hangi tarafa bırakıyor
import java.util.*;

public class Taraf {
    interface Tasiyici { }
    record Kayit(String ad, int adet) implements Tasiyici { }

    enum Islem {
        EKLE { @Override int uygula(int a) { return a + 1; } },
        TUT;
        int uygula(int a) { return a; }
    }

    public static void main(String[] args) {
        Tasiyici t = new Kayit("civata", 12);
        Object n = t;
        System.out.println("bildirilen tip Object, metne cevirme : " + n);
        Kayit a = new Kayit("civata", 12), b = new Kayit("civata", 12);
        System.out.println("a == b                               : " + (a == b));
        System.out.println("a.equals(b)                          : " + a.equals(b));
        System.out.println("karma degerleri esit mi              : " + (a.hashCode() == b.hashCode()));
        Map<Kayit, String> m = new HashMap<>();
        m.put(a, "birinci");
        System.out.println("b anahtariyla okunan                 : " + m.get(b));
        System.out.println();
        for (Islem i : Islem.values())
            System.out.printf("%-5s sinifi Islem'in kendisi mi: %-5s | bildiren tip: %s | uygula(1)=%d%n",
                    i, i.getClass() == Islem.class, i.getDeclaringClass().getSimpleName(), i.uygula(1));
        System.out.println("Islem.EKLE ile valueOf(\"EKLE\") ayni nesne mi: "
                + (Islem.EKLE == Islem.valueOf("EKLE")));
    }
}
```

```
bildirilen tip Object, metne cevirme : Kayit[ad=civata, adet=12]
a == b                               : false
a.equals(b)                          : true
karma degerleri esit mi              : true
b anahtariyla okunan                 : birinci

EKLE  sinifi Islem'in kendisi mi: false | bildiren tip: Islem | uygula(1)=2
TUT   sinifi Islem'in kendisi mi: true  | bildiren tip: Islem | uygula(1)=1
Islem.EKLE ile valueOf("EKLE") ayni nesne mi: true
```

İlk satır soruyu yanıtlıyor. Bildirilen tip `Object`tir ve `Object` sınıfının metne çevirme
yöntemi kaydın verdiğini vermez; buna karşılık basılan metin kaydın ürettiği biçimdir. Üretilen
`toString` bir **yeniden tanımlamadır** ve her yeniden tanımlama gibi kararı çalışma zamanı
tipine bırakır. Kayıt genişletilemez olduğu için o tip **bilinen tek tiptir**, ama karar yine
de o taraftan gelir. Genişletilememe kararın tarafını değiştirmez; yanıtın **önceden
bilinebilir** olmasını sağlar.

Sonraki dört satır üretilen eşitliğin ne olduğunu gösteriyor. `a` ile `b` ayrı ayrı kurulmuş
iki nesnedir ve `==` **yanlış** verir: kimlik ayrıdır. `equals` ise **doğru** verir, çünkü
üretilen gerçekleştirim bileşenleri karşılaştırır. Karma değerleri de eşittir ve bunun
gözlenebilir sonucu son satırdadır: `a` ile eklenen bir eşleme girişi `b` ile okunabiliyor.
Kimlik ile eşitliğin ayrıldığı bu üç satır, bir veri taşıyıcının nasıl davranması gerektiğinin
tanımıdır ve kaynakta tek bir karakteri yazılmamıştır.

Numaralandırmada aynı soru ters uçtan sorulur. `EKLE` ile `TUT` aynı bildirilen tiptedir, ama
`EKLE`nin çalışma zamanı sınıfı **numaralandırmanın kendisi değildir**: gövde yazılan bir sabit
kendi sınıfını alır. `TUT` içinse ikisi aynıdır. İki sabit aynı yöntem çağrısına ayrı yanıtlar
veriyor — **2** ve **1** — ve yanıtı veren şey yine çalışma zamanı tipidir. Bildiren tip her
ikisinde de `Islem` olarak kalır; bu, bildirilen tiple çalışma zamanı tipinin ayrıldığı yerde
sabitin hangi kümeye ait olduğunun kaybolmadığını gösterir. Son satır ise kümenin sabit
oluşunu ölçer: adla bulunan sabit `==` ile aynı nesnedir, çünkü her sabitten bir tane vardır.

İki biçimin bu derste yan yana durmasının nedeni buradan okunur. Kayıt **kaç tane olduğu
bilinmeyen** taşıyıcılar için yazılır ve her birinin kimliğini değerine bırakır; numaralandırma
**kaç tane olduğu bilinen** bir küme tanımlar ve her birinin kimliğini kendinde tutar. Birinde
`equals` doğruyken `==` yanlış olabilir, ötekinde ikisi hep birlikte yanıt verir. Ortak yanları
üretilen üyelerin kaynağıdır: iki bildirim de derleyiciye bir yüzey ürettirir ve üretilen
yüzeyin kararı çalışma zamanı tipinden gelir.

## Sınırlayıcı Ölçüm: Kayıt Sığ Değiştirilemezdir

Üretilen alanların hepsi `final`dı ve üretilen eşitlik bileşenleri karşılaştırıyordu. Bu iki
gerçek birlikte okunduğunda bir kayıt "değiştirilemez" görünür. Sınır tam buradadır.

```java
// Sig.java — kayıt sığ değiştirilemezdir
import java.util.Arrays;

public class Sig {
    record Parti(String ad, int[] adetler) { }

    record Guvenli(String ad, int[] adetler) {
        Guvenli { adetler = adetler.clone(); }
    }

    public static void main(String[] args) {
        int[] disari = {1, 2, 3};
        Parti p = new Parti("civata", disari);
        Guvenli g = new Guvenli("civata", disari);
        System.out.println("kurulustan sonra    : " + Arrays.toString(p.adetler())
                + " | kopyalayan: " + Arrays.toString(g.adetler()));
        disari[0] = 99;
        System.out.println("disaridan yazildi   : " + Arrays.toString(p.adetler())
                + " | kopyalayan: " + Arrays.toString(g.adetler()));
        System.out.println();
        Parti q = new Parti("civata", new int[] {99, 2, 3});
        System.out.println("ad alanlari esit mi : " + p.ad().equals(q.ad()));
        System.out.println("dizi icerigi esit mi: " + Arrays.equals(p.adetler(), q.adetler()));
        System.out.println("p.equals(q)         : " + p.equals(q));
    }
}
```

```
kurulustan sonra    : [1, 2, 3] | kopyalayan: [1, 2, 3]
disaridan yazildi   : [99, 2, 3] | kopyalayan: [1, 2, 3]

ad alanlari esit mi : true
dizi icerigi esit mi: true
p.equals(q)         : false
```

`p` kurulduktan sonra hiçbir üyesine yazılmadı; yine de `adetler` bileşeni değişti. Değişikliği
yapan taraf kaydı hiç görmedi bile — elindeki dizi üzerine yazdı ve kayıt aynı diziyi tutuyordu.
`final` alan, önceki derste ölçüldüğü gibi yalnız bağlamayı korur; bağın ucundaki nesne bu
kısıtın dışındadır. Kayıt bu kısıtı bileşen başına uygular, dolayısıyla koruması bileşenlerin
tipi kadardır — **sığdır**.

Alt üç satır aynı sınırı eşitlik tarafında gösteriyor. `p` ile `q` artık aynı adı ve aynı
içerikte bir diziyi taşıyor; iki karşılaştırma da doğru veriyor. Buna karşılık `p.equals(q)`
**yanlış**tır. Üretilen eşitlik her bileşeni o bileşenin kendi eşitliğiyle karşılaştırır; bir
dizinin kendi eşitliği ise kimliktir. Aynı kayıt tipi içinde bir bileşen değere, öteki kimliğe
bakıyor ve bu ayrım kaynakta hiçbir yerde yazılı değil.

İki kusurun da çaresi aynı yerdedir. `Guvenli` kaydı asıl yapıcısında diziyi kopyalar ve
dışarıdaki değişiklikten etkilenmez; çıktının ikinci satırı bunu gösteriyor. Derleyicinin
ürettiği şey bir başlangıç noktasıdır, bir güvence değil: üretilen üyeler bileşenlerin
davranışını devralır, düzeltmek yazan tarafa kalır.

## Özet

- Gövdesi boş, tek satırlık bir kayıt bildirimi sınıf dosyasında **üç alan** ve **yedi
  yöntem** üretir; üç alanın üçü de `final` bayrağını taşır.
- Üretilen yedi yöntem üç bileşen okuyucusu, üç ortak yüzey yöntemi (`toString`, `hashCode`,
  `equals`) ve bileşenleri alan asıl yapıcıdır.
- Kayıt genişletilemez, arayüz gerçekleştirebilir ve alanına yeniden atama derlemeyi durdurur.
- Üretilen üyeler kararı **çalışma zamanı tipine** bırakır: bildirilen tip `Object` olduğunda
  bile basılan metin kaydın ürettiği biçimdir. Genişletilememe kararın tarafını değiştirmez,
  yanıtı önceden bilinebilir kılar.
- Ayrı ayrı kurulan iki kayıt için `==` yanlış, `equals` doğrudur ve karma değerleri eşittir;
  numaralandırmada ise gövde yazılan sabit kendi sınıfını alır ve aynı çağrıya ayrı yanıt verir.
- Kaydın koruması sığdır: dizi bileşeni dışarıdan değişir ve üretilen eşitlik o bileşende
  değere değil kimliğe bakar; asıl yapıcıda kopyalamak ikisini de düzeltir.

## Sonraki Adım

Bu konu boyunca ölçülen şey hep aynı soruydu: kararı bildirilen tip mi verdi, çalışma zamanı
tipi mi. Son iki derste soruya bir taraf daha katıldı — derleyicinin kendisi. Gizli alanları,
yapıcı parametrelerini ve bir veri taşıyıcının bütün yüzeyini o üretti; ürettiklerinin hepsi
sınıf dosyasında durdu ve çalışma zamanında okunabildi. Öyleyse derleyicinin elindeki bir
başka bilgiye, **tip bilgisinin kendisine** ne oluyor? Bir kabın hangi tipte öğe tuttuğu
kaynakta yazılıdır ve derleyici o yazıya bakarak denetim yapar. Sıradaki konu bu bilginin
çalışma zamanında ne kadarının kaldığını ölçer: iki ayrı tip parametresiyle yazılmış iki kap
çalışma zamanında ayırt edilebiliyor mu, ve denetimi yapan taraf ortadan kalktığında yanlış
yazmanın bedelini kim ödüyor?
