---
title: 'Mühürlü Tipler ve Numaralandırmalar'
source: 'https://academia.sh/tr/kurslar/kotlin/muhurlu-tipler-ve-numaralandirmalar'
course: 'Kotlin Dili'
language: tr
updated: '2026-10-21T05:02:41+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Numaralandırmanın entries, ordinal ve valueOf davranışını ve girdilerin tekil olduğunu ölçer'
    - 'Mühürlü arayüz üzerindeki tümlü when ifadesinin eksik dalı derleme sırasında reddettiğini gösterir'
    - 'data object, veri sınıfı ve sıradan sınıf alt tiplerinin üç ayrı ölçüt verdiğini ölçer'
    - 'Ölçütü hiyerarşinin değil alt tipin türünün belirlediğini sınırlayıcı ölçümle doğrular'
---

# Mühürlü Tipler ve Numaralandırmalar

Numaralandırma girdisinin, data object nesnesinin, veri sınıfının ve sıradan sınıfın aynı mühürlü hiyerarşide hangi ölçüte düştüğünün ve tümlü when'in eksik dalı reddedişinin ölçümü.

Önceki ders veri sınıfının `equals`'i birincil yapıcıdaki özelliklerden ürettiğini ve ölçütün alan tiplerine bağlı olduğunu gösterdi. Şimdiye kadar ölçülen her sınıf, kaç örneği olursa olsun açık bir tipti: ayrı bir örnek her yerde kurulabilir. Bir değerin yalnızca önceden sayılmış birkaç biçimden biri olabildiği durumlar için Kotlin iki araç sunar: `enum class` ile numaralandırmalar ve `sealed` anahtar sözcüğüyle mühürlü sınıflar ve arayüzler. Bu ders ikisini ölçer ve her birinin ölçüte nasıl düştüğüne bakar.

Ölçü ekseni aynı kalır: bir değerin kendisine eşit sayılan başka bir değerle ilişkisi, yani **ölçüt**. `Criterion` sınıfı açılış dersindeki hâliyle aşağıda yeniden verilir. Kural sırayla işler: ilk değer ikiziyle aynı nesneyse tekil; değilse ve ikiz eşit değilse kimlik; ikiz eşit ama üçüncü değer eşit değilse içerik; üçüncü değer de eşitse kısmi içerik. Bu ders, önceki üç dersin kesitlerini tek hiyerarşide bir araya getirir.

```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 }}")
    }
}
```

## Numaralandırma

Numaralandırma, sınıfın bütün örneklerinin tanımda tek tek sayıldığı bir sınıftır. `enum class Level { LOW, MEDIUM, HIGH }` tam üç `Level` değeri tanımlar ve dışarıdan dördüncüsü kurulamaz. Her girdi sınıfın tek örneğidir. `entries` bütün girdileri tanım sırasıyla verir, `ordinal` sıra numarasını sıfırdan başlayarak döndürür, `valueOf` bir dizgiden girdiyi bulur ve bulamazsa istisna fırlatır.

Aşağıdaki blok bunları dener. `describe` fonksiyonu `when` ile her girdiye bir dizgi eşler ve `else` dalı yoktur: derleyici üç girdinin hepsinin karşılandığını bilir. Blok ayrıca `valueOf("MEDIUM")` ile bulunan girdinin kodda doğrudan yazılan `Level.MEDIUM` ile aynı nesne olup olmadığını `===` ile sorar. Tanımsız bir ad verilince fırlayan istisna yakalanır ve yalnızca sınıf adı basılır.

```kotlin
// Main.kt — numaralandirma
enum class Level { LOW, MEDIUM, HIGH }

fun describe(level: Level): String = when (level) {
    Level.LOW -> "dusuk"
    Level.MEDIUM -> "orta"
    Level.HIGH -> "yuksek"
}

fun main() {
    println(Level.entries)
    println(Level.HIGH.ordinal)
    println(Level.valueOf("MEDIUM"))
    println(Level.valueOf("MEDIUM") === Level.MEDIUM)
    println(describe(Level.LOW))
    try {
        Level.valueOf("EXTREME")
    } catch (e: IllegalArgumentException) {
        println(e::class.simpleName)
    }
}
```

```
[LOW, MEDIUM, HIGH]
2
MEDIUM
true
dusuk
IllegalArgumentException
```

`entries` üç girdiyi sırayla verir, `HIGH` ikinci sıfırdan sayılınca 2 numaralıdır ve `valueOf` ile bulunan girdi doğrudan yazılanla aynı nesnedir. Bu, ölçütün ilk sorusudur: girdi kendisinin ikizidir ve ölçüt tekildir. Tanımsız ad `IllegalArgumentException` fırlatır.

**TN19.** Ölçüm yalnızca üç girdili, alanı ve yöntemi olmayan bir numaralandırma içindir. Girdilerin kendi alanları ya da yöntemleri olduğunda, ya da numaralandırma bir arayüz uyguladığında davranışın aynı kalıp kalmadığı ölçülmedi.

## Mühürlü Arayüz ve Tümlü When

`sealed interface Shape`, `Shape`'i uygulayabilecek tüm tiplerin aynı pakette ve aynı derlemede önceden bilindiği bir arayüzdür. Aşağıdaki hiyerarşi üç alt tipten oluşur: `data object Empty` tek bir örneği olan bir nesne bildirimidir, `data class Circle` bir veri sınıfıdır, `class Blob` ise `equals`'i yazılmamış sıradan bir sınıftır. Bu üç tip, önceki dersleri tek hiyerarşide toplar. Derleyici alt tiplerin tam listesini bildiği için `when (shape)` ifadesinin hepsini karşılayıp karşılamadığını denetleyebilir.

```kotlin
// Main.kt — kapali hiyerarsi
sealed interface Shape
data object Empty : Shape
data class Circle(val radius: Int) : Shape
class Blob(val size: Int) : Shape

fun describe(shape: Shape): String = when (shape) {
    Empty -> "bos"
    is Circle -> "daire " + shape.radius
    is Blob -> "leke " + shape.size
}

fun main() {
    val shapes = listOf(Empty, Circle(2), Blob(3))
    for (shape in shapes) println(describe(shape))
    println(Empty)
    println(Circle(2))
}
```

```
bos
daire 2
leke 3
Empty
Circle(radius=2)
```

Üç dal üç alt tipi karşılar ve `else` yazılmaz. `println(Empty)` yalnızca adı basar: `data object`, `toString` yöntemini nesnenin adıyla üretir. `println(Circle(2))` ise veri sınıfının alanlı biçimini basar. Sıradan bir `object` için varsayılan `toString` bir ad ve karma kodu verirdi; `data` değiştiricisi bunu okunur kılar.

Tümlü `when`'in asıl değeri başka yerdedir: hiyerarşiye bir alt tip eklenip dallardan biri unutulursa derleyici reddeder. Aşağıdaki parça `Blob` dalını bırakır. Parça, açılış dersinde olduğu gibi ölçüldü ve derlenmedi; derleyici eksik dalı adıyla gösteren bir hata verdi. Hata metni burada basılmaz.

```kotlin
sealed interface Shape
data object Empty : Shape
data class Circle(val radius: Int) : Shape
class Blob(val size: Int) : Shape

fun describe(shape: Shape): String = when (shape) {
    Empty -> "bos"
    is Circle -> "daire " + shape.radius
}

fun main() {
    println(describe(Empty))
}
```

**TN20.** Derleme reddi Kotlin 2.4.21'de ölçüldü. `when` bir ifade olarak kullanılmadığında, yalnızca deyim olduğunda, aynı denetimin uygulanıp uygulanmadığı bu derste ölçülmedi.

## Alanlı Numaralandırma

Numaralandırma girdileri alan ve yöntem taşıyabilir. Girdiler parantez içinde yapıcı değerleri alır, girdi listesi `;` ile biter ve ardından üyeler gelir. Aşağıdaki blok boyut ve kod taşıyan bir numaralandırmayı dener: girdi üzerinde yöntem çağırır, `entries` üzerinde dönüştürme yapar, girdileri sıra numarasıyla kıyaslar ve olmayan bir kodu arar.

```kotlin
// Main.kt — alanli numaralandirma
enum class Planet(val code: String, val size: Int) {
    SMALL("s", 1),
    MEDIUM("m", 5),
    LARGE("l", 9);

    fun isBigger(other: Planet): Boolean = size > other.size
}

fun main() {
    println(Planet.LARGE.isBigger(Planet.SMALL))
    println(Planet.entries.map { it.code })
    println(Planet.entries.maxByOrNull { it.size })
    println(Planet.MEDIUM.name + Planet.MEDIUM.ordinal)
    println(Planet.SMALL < Planet.LARGE)
    println(Planet.entries.firstOrNull { it.code == "x" })
    println(Planet.entries.firstOrNull { it.code == "x" }?.name ?: "yok")
}
```

```
true
[s, m, l]
LARGE
MEDIUM1
true
null
yok
```

`LARGE.isBigger(SMALL)` `true` verir; yöntem, girdinin kendi `size` alanını kullanır. `entries` girdileri tanım sırasıyla verir, dolayısıyla kodların listesi `[s, m, l]` çıkar. `maxByOrNull` en büyük boyutlu girdiyi bulur ve `LARGE` basar. `name` ile `ordinal` birleşince `MEDIUM1` elde edilir: ikinci girdinin sırası `1`'dir. `SMALL < LARGE` `true` verir, çünkü girdiler sıra numarasına göre karşılaştırılabilir. Olmayan bir kod aranınca sonuç `null` olur; `?.name ?: "yok"` bunu `yok`'a çevirir.

Numaralandırma burada kapalı ve sabit bir değerler kümesidir ve her girdi tek bir örnektir. Alan eklemek, girdilerin tanımlandığı satırda değer vermek anlamına gelir; girdi listesi `;` ile bitirilmeden üye yazılamaz. Aramanın `null` dönmesi aynı zamanda `valueOf`'tan farkı gösterir: `valueOf` olmayan ada istisna fırlatır, `firstOrNull` ise yokluğu değer olarak taşır. Hangisinin seçileceği, yokluğun hata mı yoksa beklenen bir durum mu olduğuna bağlıdır.

## Else Dalı Tümlülüğü Susturur

Tümlü `when`'in eksik dalı reddetmesi bir güvencedir; ama bu güvence `else` yazıldığı anda kaybolur. Aşağıdaki blok yukarıda reddedilen hiyerarşinin aynısını kullanır ve `Blob` dalı yerine bir `else` koyar. Derleme bu kez geçer. Bloğun gösterdiği, sonradan bir alt tip eklendiğinde ne olacağıdır: o alt tip sessizce `else` dalına düşer.

```kotlin
sealed interface Shape
data object Empty : Shape
data class Circle(val radius: Int) : Shape
class Blob(val size: Int) : Shape

fun describe(shape: Shape): String = when (shape) {
    Empty -> "bos"
    is Circle -> "daire"
    else -> "bilinmiyor"
}

fun main() {
    println(describe(Empty))
    println(describe(Circle(1)))
    println(describe(Blob(1)))
}
```

```
bos
daire
bilinmiyor
```

Çıktı `bos`, `daire`, `bilinmiyor` olur. Derleme geçti, çünkü `else` her kalan durumu karşılar. `Blob` örneği `bilinmiyor` dalına düştü; yukarıdaki tümlü sürümde bu durum derleme hatasıydı. Fark, `else` dalının derleyicinin eksik alt tip denetimini kapatmasıdır.

Sorun bugünün kodunda değil, yarının değişikliğinde ortaya çıkar. Hiyerarşiye sonradan eklenen bir alt tip, `else` dalı olan her `when` ifadesinde sessizce o dala düşer ve derleyici hiçbir uyarı vermez. Tümlü ifadede aynı ekleme, ilgili her `when` ifadesini derleme hatasıyla işaretlerdi. Sık yapılan hata, "her ihtimale karşı" diye `else` eklemektir. Mühürlü tipin sağladığı güvence tam da bu dalı yazmamaktan gelir. Gerçekten varsayılan bir davranış gerekiyorsa o davranış açık bir alt tip olarak modellenir, `else` bu işi sessizce üstlenmez.

## Mühürlü Sınıf ve Akıllı Tip Dönüşümü

Mühürlü arayüzün yanı sıra `sealed class` da vardır; fark, sınıfın yapıcı durumu taşıyabilmesidir. Alt tipler genellikle sınıfın içine yazılır. Aşağıdaki `Outcome` üç durumu anlatır: değer taşıyan başarı, neden taşıyan hata ve durum taşımayan bekleme. Tümlü `when`, her dalda alt tipe akıllı tip dönüşümü yapar ve `outcome.value` gibi alanlara doğrudan erişir.

```kotlin
// Main.kt — muhurlu sinif ve akilli tip donusumu
sealed class Outcome {
    data class Success(val value: Int) : Outcome()
    data class Failure(val reason: String) : Outcome()
    data object Pending : Outcome()
}

fun render(outcome: Outcome): String = when (outcome) {
    is Outcome.Success -> "deger " + (outcome.value + 1)
    is Outcome.Failure -> "hata " + outcome.reason.length
    Outcome.Pending -> "bekliyor"
}

fun main() {
    val outcomes = listOf(Outcome.Success(1), Outcome.Failure("kotu"), Outcome.Pending)
    for (outcome in outcomes) println(render(outcome))
    println(Outcome.Pending === Outcome.Pending)
    println(outcomes.filterIsInstance<Outcome.Success>().size)
    println(outcomes.count { it is Outcome.Failure })
}
```

```
deger 2
hata 4
bekliyor
true
1
1
```

`sealed class` ile `sealed interface` aynı güvenceyi sağlar: alt tipler derleme anında bilinir. Fark, sınıfın yapıcı durumu ve üst sınıf davranışı taşıyabilmesidir. Çıktıda üç dal çalışır: `deger 2`, `hata 4` ve `bekliyor`. Her dalda derleyici, `outcome` değerini o dalın alt tipine daraltır; bu yüzden `outcome.value` ve `outcome.reason` doğrudan yazılabilir, ayrıca dönüşüm gerekmez.

Dördüncü satır `Pending === Pending` ifadesini sorar ve `true` döner: `data object` tek bir örnektir, bu yüzden kimlik ve içerik eşitliği örtüşür. Son iki satır koleksiyon fonksiyonlarıyla hiyerarşiyi süzer: `filterIsInstance` ve `is` ile sayım ikisi de `1` verir. İç içe yazım alt tiplerin adını `Outcome.Success` biçimine sokar. Bu, alt tiplerin hiyerarşiye ait olduğunu görünür kılar ve aynı ada sahip başka bir tipin karışmasını önler. Alt tipler aynı pakette olduğu sürece dışarıya da yazılabilir; ama iç içe yazım, tümlülüğün nereye bakıldığını okuyan kişiye gösterir.

## Numaralandırma Koleksiyonlarda

Numaralandırma girdileri tekil olduğu için koleksiyonlarda anahtar olarak kullanılması sorunsuzdur. Girdiler `Comparable` olduğundan sıra numarasına göre sıralanır. Blok bir listede tekrarlanan girdileri sayar, sıralar ve ayırır, sonra iki girdinin sırasını `compareTo` ile sorar.

```kotlin
// Main.kt — numaralandirma koleksiyonlarda
enum class Level { LOW, MEDIUM, HIGH }

fun main() {
    val levels = listOf(Level.HIGH, Level.LOW, Level.HIGH, Level.MEDIUM)
    println(levels.groupingBy { it }.eachCount())
    println(levels.sorted())
    println(levels.distinct().size)
    println(Level.HIGH.compareTo(Level.LOW))
    println(Level.valueOf("LOW") == Level.LOW)
}
```

```
{HIGH=2, LOW=1, MEDIUM=1}
[LOW, MEDIUM, HIGH, HIGH]
3
2
true
```

`groupingBy { it }.eachCount()` girdileri sayar ve ilk görülme sırasını korur: `{HIGH=2, LOW=1, MEDIUM=1}`. Girdiler tekil olduğu için anahtar olarak güvenle kullanılır; iki `HIGH` aynı örneğe işaret eder ve tek anahtara toplanır. `sorted` girdileri sıra numarasına göre dizer, `[LOW, MEDIUM, HIGH, HIGH]` çıkar. `distinct` üç girdi bırakır. `HIGH.compareTo(LOW)` bu örnekte `2` verir, sıra numaraları farkıyla uyumlu bir değer. `valueOf("LOW") == LOW` ise `true`'dur, çünkü ad aynı örneği döndürür.

Buradaki mekanizma, numaralandırmanın hem tekil hem sıralı olmasıdır. Sıralama tanım sırasına bağlıdır, yani girdilerin dosyadaki konumu davranışın parçasıdır. Sık yapılan hata, girdileri sonradan araya yerleştirmek ve sıralamaya dayanan kodu bozmaktır: sıra numarası değişince `sorted` sonucu da, `compareTo` değeri de değişir. Sıralamanın önemli olduğu bir numaralandırmada eklenecek girdi sona eklenir, ya da sıra açık bir alanda tutulur ve karşılaştırma o alan üzerinden yapılır.

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

Üç alt tip aynı mühürlü arayüzün altındadır. Mühür, kimin alt tip olabileceğini kapatır; ama `equals`'i belirlemez. O hâlde aynı hiyerarşi aynı anda birden fazla ölçüt vermelidir. Sınırlayıcı ölçüm bunu dört satırla dener. İlk satır bir numaralandırma girdisini `valueOf` ile bulunan ikiziyle karşılaştırır. Sonraki üç satır `Shape` alt tiplerini sırayla dener: `Empty`, `Circle(1)` ve `Blob(1)`. Her alt tipte ikiz aynı değerle ayrıca kurulur, üçüncü değerin değeri farklıdır; `Empty` için üçüncü değer olarak `Circle(1)` verilir çünkü `Empty`'nin başka örneği yoktur.

```kotlin
// Main.kt — alt tipin turu
sealed interface Shape
data object Empty : Shape
data class Circle(val radius: Int) : Shape
class Blob(val size: Int) : Shape

enum class Level { LOW, MEDIUM, HIGH }

fun main() {
    val checks = listOf(
        Criterion("girdi", Level.HIGH, Level.valueOf("HIGH"), Level.LOW),
        Criterion("data-object", Empty, Empty, Circle(1)),
        Criterion("data-class", Circle(1), Circle(1), Circle(2)),
        Criterion("sinif", Blob(1), Blob(1), Blob(2)),
    )
    for (check in checks) check.report()
    summarize(checks)
}
```

```
girdi: ayni-nesne=true, ikiz=true, farkli=false -> tekil
data-object: ayni-nesne=true, ikiz=true, farkli=false -> tekil
data-class: ayni-nesne=false, ikiz=true, farkli=false -> icerik
sinif: ayni-nesne=false, ikiz=false, farkli=false -> kimlik
tekil: 2
kimlik: 1
icerik: 1
kismi-icerik: 0
```

Aynı hiyerarşi üç ayrı ölçüt verir. Numaralandırma girdisi de `data object` de tek örnekli olduğu için tekildir: ikiz zaten aynı nesnedir. `Circle` veri sınıfı olduğu için içerik verir. `Blob`'un `equals`'i yazılmamıştır; aynı değerli iki örnek farklı nesnedir ve ölçüt kimliktir. Ölçütü mühür belirlemez; alt tipin hangi türde yazıldığı belirler. Tekil, kimlik ve içerik tek bir `when` ile işlenen tek bir arayüzün altında yan yana durabilir. Dağılım 2 tekil, 1 kimlik, 1 içerik, 0 kısmi içeriktir.

## Özet

- Numaralandırma girdileri sınıfın tek örnekleridir: `valueOf` ile bulunan girdi doğrudan yazılanla aynı nesnedir ve ölçüt tekildir.
- `entries`, `ordinal` ve `valueOf` girdileri tanım sırasıyla listeler, sıralar ve ada göre bulur; tanımsız ad `IllegalArgumentException` fırlatır.
- Mühürlü arayüzde alt tiplerin listesi derleyici tarafından bilinir; tümlü `when` eksik bir dalı derleme sırasında reddeder.
- `data object` tekil, veri sınıfı alt tipi içerik, `equals`'i yazılmamış sıradan sınıf alt tipi kimlik verir.
- Bu dersin ölçütü: **tekil**. Sınırlayıcı ölçümde aynı mühürlü hiyerarşi üç ölçütü birden verdi; ölçütü hiyerarşi değil alt tipin türü belirler.

## Sonraki Adım

`data object Empty`, tek örnekli bir nesneyi bildirimle kurdu. Kotlin'de bu kalıbın genel biçimi `object` bildirimidir: sınıfı ve tek örneğini birlikte tanımlar. Bir sonraki ders nesne bildirimlerini, bir sınıfın içindeki yardımcı nesneyi ve ad vermeden kurulan nesne ifadesini ölçer ve üçünün ölçüte nasıl düştüğüne bakar.
