---
title: 'Nesne Bildirimleri'
source: 'https://academia.sh/tr/kurslar/kotlin/nesne-bildirimleri'
course: 'Kotlin Dili'
language: tr
updated: '2026-10-21T05:02:40+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir nesne bildirimini yazmak ve iki kez okunan değerin tek nesne olduğunu ölçmek'
    - 'Yardımcı nesneyi (`companion object`) ve onun fabrika fonksiyonunu birbirinden ayırmak'
    - '`data object` bildiriminin `toString` çıktısını ve eşitliğini okumak'
    - 'Nesne bildirimi ile nesne ifadesinin aynı sözcükle yazıldığı hâlde farklı davrandığını açıklamak'
---

# Nesne Bildirimleri

Nesne bildirimi, yardımcı nesne, `data object` ve nesne ifadesini iki değeri eşit yapan ölçütle ölçer; bildirimin tekil, ifadenin her değerlendirmede yeni nesne olduğunu gösterir.

Önceki derste, "Mühürlü Tipler ve Numaralandırmalar" dersinde, numaralandırma girdisi ve `data object` değerlerinin tekil olduğunu gördük: aynı girdiyi iki kez okuyunca aynı nesne geliyordu. Bu ders o tekilliğin kaynağına iniyor. `object` sözcüğü Kotlin'de üç ayrı yerde karşınıza çıkar: bir bildirimde, bir sınıfın içinde yardımcı nesne olarak ve bir ifadenin başında. Üçü de aynı sözcükle yazılır; bu ders üçünün aynı şeyi yapıp yapmadığını ölçüyor.

Ölçü, bu kursun her dersinde aynı soru: bu iki değeri eşit yapan ne? Dört olası cevap var: aynı nesne olmaları (tekil), eşitliğin kimliğe dayanması (kimlik), içeriklerinin eşit olması (içerik) ve yalnız bazı içeriklerin eşit olması (kısmi içerik).

**Nesne bildirimi (object declaration)**, bir tipi tanımlar ve o tipin tek örneğini aynı anda kurar. Bildirimin adı hem tipin hem de o tek değerin adıdır. Yapıcı çağrılmaz; adı yazmak değerin kendisini okumaktır.

## Ölçüm Düzeneği

`Criterion` her derste aynı biçimde ilk blokta durur. Her gözlem üç değer alır: `first`, `twin` (aynı tarifle ayrıca kurulan değer) ve `other` (yalnız bir bakımdan farklı değer). Kural sonucu görür, gerekçeyi görmez: `first === twin` ise `tekil`; değilse ve `first == twin` yanlışsa `kimlik`; `first == other` yanlışsa `icerik`; hiçbiri değilse `kismi-icerik`.

```kotlin
// Criterion.kt — iki degeri esit yapan olcutu siniflandirir
class Criterion(val label: String, first: Any?, twin: Any?, other: Any?) {
    val sameObject = first === twin
    val equalTwin = first == twin
    val equalOther = first == other

    val name: String = when {
        sameObject -> "tekil"
        !equalTwin -> "kimlik"
        !equalOther -> "icerik"
        else -> "kismi-icerik"
    }

    fun report() {
        println("$label: ayni-nesne=$sameObject, ikiz=$equalTwin, farkli=$equalOther -> $name")
    }
}

fun summarize(checks: List<Criterion>) {
    for (name in listOf("tekil", "kimlik", "icerik", "kismi-icerik")) {
        println("$name: ${checks.count { it.name == name }}")
    }
}
```

**TN21.** Bir nesne bildiriminde `twin` ayrıca kurulamaz, çünkü ikinci bir örnek yoktur; bu derste `twin` olarak aynı bildirimin ikinci kez okunan değerini verdik. `other` olarak aynı gövdeli ama ayrı adlı bir bildirim kullandık.

## Bildirim Tek Nesnedir

Aşağıdaki blok iki nesne bildirimi yazar. `IdSource` bir sayaç tutar; `OtherSource` aynı gövdeye sahip ayrı bir bildirimdir. `IdSource` iki ayrı değişkene okunur, sayaç da bu iki değişken ve doğrudan adı üzerinden ilerletilir.

```kotlin
// Main.kt — nesne bildirimi iki kez okunur
object IdSource {
    private var next = 1
    fun take(): Int = next++
}

object OtherSource {
    private var next = 1
    fun take(): Int = next++
}

fun main() {
    val a = IdSource
    val b = IdSource
    println(a.take())
    println(b.take())
    println(IdSource.take())
    Criterion("nesne-bildirimi", a, b, OtherSource).report()
}
```

```
1
2
3
nesne-bildirimi: ayni-nesne=true, ikiz=true, farkli=false -> tekil
```

Üç `take()` çağrısı, hangi değişken üzerinden yapılırsa yapılsın aynı sayacı ilerletti, çünkü `a` ve `b` aynı nesneyi gösteriyor. Kural da bunu `tekil` olarak yazdı: `===` doğru çıktığı için ikizin eşitliğine bakılmadı bile. `OtherSource`'un sayacı ayrı olduğu için o, ilk nesneye eşit değil.

Bildirim bir yapıcı çağrısı olmadığından, adın sonuna parantez koymak da çalışmaz. Önce bunu doğruladık: aşağıdaki parça Kotlin 2.4.21'de derlenmedi, bu yüzden çıktısız kalıyor.

```kotlin
object IdSource

fun main() {
    val source = IdSource()
}
```

**TN22.** Reddin hata metnini derse yazmıyoruz; yalnız parçanın derlenmediği doğrulandı. Bildirimin başka bir sınıftan kalıtım alıp alamayacağı ya da bir arayüz gerçekleştirip gerçekleştirmeyeceği bu derste ölçülmedi.

## Yardımcı Nesne ve Fabrika

**Yardımcı nesne (companion object)**, bir sınıfın içinde `companion object` diye yazılan nesne bildirimidir. Sınıf adıyla çağrılabilen üyeleri tutar. Bildirim olduğu için tekildir. Ama içine yazılan bir fabrika fonksiyonu, sınıfın örneklerini kurar ve o örnekler tekil değildir. İkisini yan yana ölçüyoruz.

```kotlin
// Main.kt — yardimci nesne tekildir, fabrika her seferinde yeni nesne uretir
class Account private constructor(val owner: String) {
    companion object {
        fun open(owner: String): Account = Account(owner)
    }
}

fun main() {
    val checks = listOf(
        Criterion("yardimci-nesne", Account.Companion, Account.Companion, Any()),
        Criterion("fabrika-sonucu", Account.open("ada"), Account.open("ada"), Account.open("can")),
    )
    for (check in checks) check.report()
    summarize(checks)
}
```

```
yardimci-nesne: ayni-nesne=true, ikiz=true, farkli=false -> tekil
fabrika-sonucu: ayni-nesne=false, ikiz=false, farkli=false -> kimlik
tekil: 1
kimlik: 1
icerik: 0
kismi-icerik: 0
```

`yardimci-nesne` satırı `tekil`, `fabrika-sonucu` satırı `kimlik` çıktı. Aynı sınıfın içinde yazılan iki `object` karşılığı, iki ayrı ölçüt verdi: yardımcı nesnenin kendisi tek, onun ürettiği hesaplar her çağrıda ayrı. İki `Account`'un sahibi aynı olsa bile `==` doğru dönmedi, çünkü `Account` sıradan bir sınıftır ve `equals`'ü yeniden tanımlamaz; eşitlik kimliğe düşer. Bu, kural dilinde `kimlik` demektir. Yapıcıyı özel yapmak (`private constructor`) örnek kurma yolunu yardımcı nesnenin fonksiyonuna daralttı; fabrika böylece tek giriş kapısı oldu.

**TN23.** Fabrikanın her çağrıda yeni bir `Account` kurduğu burada yalnız bu sınıf için ölçüldü. Bir fabrikanın önceden kurulmuş bir örneği döndürmesi de mümkündür; o durumda ölçüt `tekil` olurdu, ama bu derste öyle bir fabrika yazmadık.

## data object

`data object`, bir nesne bildirimine veri sınıfının okunabilir `toString`'ini ve `equals`/`hashCode`'unu ekler. Düz bir `object`'in varsayılan `toString` çıktısını bu kursta basmıyoruz; `data object` ise yalnız adını yazar. Mühürlü hiyerarşilerde durum nesnelerine `data object` yazılmasının nedeni budur: çıktıda okunur bir ad görünür.

```kotlin
// Main.kt — data object okunabilir bir toString tasir
data object Accepted

fun main() {
    println(Accepted)
    println(Accepted == Accepted)
    val checks = listOf(Criterion("data-object", Accepted, Accepted, "Accepted"))
    for (check in checks) check.report()
}
```

```
Accepted
true
data-object: ayni-nesne=true, ikiz=true, farkli=false -> tekil
```

Çıktının ilk satırı bildirimin adından başka bir şey içermiyor. Ölçüt yine `tekil`: `data object` yeni bir örnek üretmez, yalnız mevcut tekil nesneye okunabilirlik ekler. `other` olarak verdiğimiz `"Accepted"` dizgisi ise `Accepted`'e eşit değil; ikisinin yazılışı aynı olsa da tipleri ayrı.

## İlk Erişimde Kurulum ve Arayüz

Bir nesne bildiriminin tek örneği ne zaman kurulur? Program başlarken mi, yoksa ilk kullanıldığı anda mı? Bu sorunun cevabı, bildirimin gövdesindeki `init` bloğunda görünür: blok her ne zaman koşarsa örnek o zaman kurulmuştur. Bildirim ayrıca bir arayüz gerçekleştirebilir, yani sıradan bir sınıf gibi davranışı sözleşmeye bağlayabilir. Son olarak bildirim, `when` ifadesinde bir sabit gibi eşleştirilebilir.

Aşağıdaki blokta `Polite`, `Greeter` arayüzünü gerçekleştiren ve kurulduğunda bir satır basan bir nesne bildirimidir. `Idle` ise bir `data object`'tir. `describe` fonksiyonu bir değeri üç yoldan eşleştirir: `Idle` ile eşitlik, `is Polite` ile tip denetimi ve geri kalan her şey. `main` ilk satırda `basladi` yazdırır; böylece `init` satırının nerede göründüğü, bildirimin hangi anda kurulduğunu gösterir.

```kotlin
// Main.kt — nesne ilk erisimde kurulur, arayuz gerceklestirir, when ile eslesir
interface Greeter {
    fun greet(name: String): String
}

object Polite : Greeter {
    init {
        println("polite kuruldu")
    }

    override fun greet(name: String): String = "merhaba " + name
}

data object Idle

fun describe(state: Any): String = when (state) {
    Idle -> "bos"
    is Polite -> "nazik"
    else -> "baska"
}

fun main() {
    println("basladi")
    val greeter: Greeter = Polite
    println(greeter.greet("ada"))
    println(Polite.greet("can"))
    println(describe(Idle))
    println(describe(Polite))
    println(describe(Any()))
    Criterion("arayuz-nesnesi", greeter, Polite, Idle).report()
}
```

```
basladi
polite kuruldu
merhaba ada
merhaba can
bos
nazik
baska
arayuz-nesnesi: ayni-nesne=true, ikiz=true, farkli=false -> tekil
```

`polite kuruldu` satırı `basladi`'dan sonra ve ilk `greet` çağrısından önce göründü. `Polite` programın başında kurulmadı: bildirim, adına ilk erişildiği anda kuruldu ve `init` bloğu o sırada koştu. İkinci erişim yeni bir satır basmadı, çünkü örnek zaten vardı. `greeter` ve `Polite` aynı nesneyi gösterdi, ölçüt `tekil` çıktı; `greeter` değişkeninin tipi `Greeter` olsa da altındaki nesne değişmedi.

`describe` üç ayrı sonuç verdi. `Idle` için `bos`, `Polite` için `nazik`, sıradan bir `Any()` için `baska` yazıldı. Bir nesne bildirimi tekil olduğu için `when` içinde sabit gibi eşleşir: `Idle ->` satırı `Idle == state` karşılaştırmasına iner. `is Polite` da çalıştı, çünkü bildirim hem bir değer hem bir tip tanımlar; tek örneği olan bir tip için ikisi aynı sonucu verir.

Bu ölçümden çıkan pratik sonuç iki yanlıdır. Birincisi, `init` bloğunda yan etki bırakmak, yani bir satır basmak ya da bir kaynağı açmak, bildirimin kurulma anını programın akışına bağlar; hangi satırın önce koşacağı ilk erişimin yerine bağlıdır. İkincisi, bir nesne bildirimi arayüz gerçekleştirdiğinde, o arayüz tipli her değişken yine aynı tek örneği taşır; bu yüzden ölçüt tipe göre farklılaşmaz, nesnenin kendisine bağlı kalır.

**TN24.** Nesne bildirimine ilk erişimin birden çok iş parçacığından aynı anda yapılması bu derste ölçülmedi; yalnız tek akışta kurulum sırası gözlendi.



## Ölçümlerden Çıkan Okuma Kuralı

Bu noktaya kadar ölçtüğümüz satırlar ve her satır aynı soruya cevap verdi: iki okuma aynı nesneyi mi veriyor? Satırları yan yana koyunca bir okuma kuralı çıkıyor. Bildirim, adı yazıldığında bir değer üretir; `Stamp`, `Polite`, `Accepted` ve `Idle` bu yüzden `tekil` çıktı. İfade ise her değerlendirildiğinde yeni bir nesne kurar; `makeMarker()` bu yüzden `kimlik` çıktı. Sınıfın fabrikası bir fonksiyondur, bildirim değildir; `Account.open` her çağrıda yeni bir `Account` kurdu ve sonuç yine `kimlik` oldu. Kural, sözcüğün yazıldığı yere bakar: ad tek bir değere gidiyorsa tekil, çağrı ya da ifade yeni değer kuruyorsa kimlik.

Sık yapılan hata bu kuralı tersine çevirmektir. Bir `object` sözcüğü gören okuyucu "bu tekildir" der; oysa `object : Tip { ... }` biçimi bir ifadedir. Tersi de yanlıştır: bir sınıf içinde `companion object` yazıldığında yardımcı nesnenin ürettikleri tekil sanılır. Ölçüm, yardımcı nesnenin kendisinin tek, onun fabrikasının ürettiklerinin ayrı olduğunu gösterdi. Bu yüzden bir tekil nesneye bağlanan durum, örneğin bir sayaç ya da bir önbellek, programın bütün parçalarınca paylaşılır; bir fabrikanın ürettiği nesneye bağlanan durum ise yalnız o nesnenin sahibine aittir.

Kurulum anı ikinci bir ayrıntıdır. `polite kuruldu` satırı ilk erişimde göründü ve ikinci erişimde görünmedi. Bir tekil nesnenin kuruluş maliyeti ya da yan etkisi, programın başında değil, ilk kullanıldığı yerde ödenir. Bu, `init` bloğuna yazdığınız şeyin ne zaman koşacağını sıralamak gerektiğinde işe yarar: sıralama, hangi koddan ilk erişildiğine bağlıdır ve o kod yer değiştirirse satır da yer değiştirir. Bu yüzden `init` bloğunu kısa tutmak, yalnız alan kurmak ve çıktı üretmemek akıllıca olur; bu derste yalnız ölçümü görünür kılmak için çıktı bastırdık.

Üçüncü ayrıntı `when` ifadesidir. `Idle` ile eşleştirme ve `is Polite` ile tip denetimi aynı işi yapar, çünkü bildirimin tek örneği vardır. Tek örneği olan bir tipte "bu değer o değere eşit mi" ile "bu değer o tipte mi" soruları aynı cevabı verir. İki örnek mümkün olan bir sınıfta bu iki soru ayrılırdı; bu ayrılmanın olmaması tekilliğin gözlenebilir bir sonucudur.

## Ölçmeden Önce Tahmin Etmek

Bir satırı koşturmadan önce ölçütü tahmin etmek, kuralı gerçekten anlayıp anlamadığınızı sınar. `Criterion` düzeneği üç soru sorar: aynı nesne verildiğinde `===` doğru mu, ikiz verildiğinde `==` doğru mu, farklı nesne verildiğinde `==` doğru mu? Nesne bildiriminde ilk soru her zaman doğru cevaplanır, çünkü ad tek bir değere gider; bu yüzden ikizin de aynı nesne olması gerekir ve üçüncü soru yalnızca farklı bir tip verildiğinde yanlış çıkar. Ölçüt `tekil` olarak yazılır.

Nesne ifadesinde ilk soru bile yanlış cevaplanır. Aynı fonksiyonu iki kez çağırmak iki ayrı nesne verir ve ikizler birbirine eşit sayılmaz; ikisi de `false` olunca ölçüt `kimlik` olur. Bu dersteki her satırı bu iki yoldan birine koyabilirsiniz: ad bir bildirimi gösteriyorsa `tekil`, bir çağrıyı ya da ifadeyi gösteriyorsa `kimlik`. `data object` satırı bile bu kuralın dışına çıkmadı; `data` önekinin eklediği şey eşitlik değil, okunabilir bir yazı oldu.

Tahminin tutmadığı yer, bir kuralı eksik hatırladığınız yerdir. Örneğin `describe` fonksiyonunda `Idle` için `bos` yazacağını bildiyseniz ama `Polite` için `nazik` yerine `baska` bekliyorsanız, `is` denetiminin bildirim adıyla çalışmadığını düşünmüşsünüz demektir. Ölçüm bu varsayımı düzeltti: bildirim hem bir değer hem bir tiptir.

## Sınırlayıcı Ölçüm

**Nesne ifadesi (object expression)**, `object` sözcüğünün bir ifadenin başında kullanılmasıdır: `object { ... }` ya da bir tip adından sonra `object : Tip { ... }`. Ad taşımaz ve ifade her değerlendirildiğinde yeni bir nesne kurar. Bildirimle ifade arasındaki fark tam burada: aynı sözcük, bildirimde tekil bir nesne, ifadede her seferinde yeni bir nesne üretir. Bu yüzden bu kursun ölçüsü onları ayırır.

```kotlin
// Main.kt — nesne ifadesi her degerlendirmede yeni nesne kurar
object Stamp

fun makeMarker(): Any = object {
    val side = 4
}

fun main() {
    val checks = listOf(
        Criterion("bildirim", Stamp, Stamp, makeMarker()),
        Criterion("ifade", makeMarker(), makeMarker(), makeMarker()),
    )
    for (check in checks) check.report()
    summarize(checks)
}
```

```
bildirim: ayni-nesne=true, ikiz=true, farkli=false -> tekil
ifade: ayni-nesne=false, ikiz=false, farkli=false -> kimlik
tekil: 1
kimlik: 1
icerik: 0
kismi-icerik: 0
```

`bildirim` satırı `tekil`, `ifade` satırı `kimlik` çıktı. İfadenin bir adı, dolayısıyla bir yapıcısı olmadığı hâlde, her `makeMarker()` çağrısı yeni bir nesne kurdu ve bu nesneler `equals`'ü yeniden tanımlamadığı için birbirine eşit çıkmadı. Bu ölçüm bir sınırdır: `object` sözcüğünü gördüğünüzde tekil olduğunu varsaymak yetmez; sözcüğün bildirimde mi yoksa ifadede mi durduğuna bakmak gerekir.

**TN25.** Nesne ifadesinin yakaladığı bir değişkenin nasıl göründüğü ve ifadenin bir tipi genişletmesi bu derste ölçülmedi; yalnız adsız, tipsiz bir ifade kullanıldı.

## Özet

- Nesne bildirimi bir tipi ve o tipin tek örneğini birlikte kurar; adı yazmak değeri okumaktır ve iki okuma aynı nesneyi verir.
- Yardımcı nesne bir sınıfın içindeki nesne bildirimidir; tekildir, ama onun fabrikası sınıfın örneklerini her çağrıda ayrı kurabilir.
- `data object`, tekil nesneye yalnız okunabilir bir `toString` ve eşitlik ekler; ölçütü değiştirmez.
- Nesne ifadesi her değerlendirmede yeni bir nesne kurar; aynı `object` sözcüğü bildirimde tekil, ifadede kimliktir.
- Bu dersin ölçütü: **tekil**. İki okuma aynı nesneyi verdiğinde `===` doğru çıkar ve eşitliğin gerekçesi aranmaz.

## Sonraki Adım

Bu derste bir nesnenin tek mi, yoksa her seferinde yeni mi kurulduğuna baktık ve davranışı yalnız sınıfın kendi gövdesinde tuttuk. Sıradaki ders davranışı bir tipten ayırıyor: arayüzler, bir sözleşmeyi yazar ve bir sınıf onu başka bir nesneye devredebilir. Devretmenin eşitliği de devredip devretmediği ölçülecek.
