---
title: 'Temel Tipler'
source: 'https://academia.sh/tr/kurslar/kotlin/temel-tipler'
course: 'Kotlin Dili'
language: tr
updated: '2026-10-21T05:02:39+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - '`Int`, `Long`, `Double`, `Char` ve `Boolean` tiplerinin rollerini ayırt etmek'
    - 'Sayı tipleri arasındaki dönüşümün açık yazıldığını ve karşılaştırmanın tipleri eşleştirmediğini göstermek'
    - 'Kutulanan sayıların `===` ile karşılaştırıldığında neden tutarsız çıktığını açıklamak'
    - '`Double.NaN` değerinin statik tipe göre farklı eşitlik verdiğini söylemek'
---

# Temel Tipler

Sayı tiplerini, karakteri ve mantıksal değeri tanıtır; boş değer alabilen `Int` kutulandığında eşitliğin ölçütünün değiştiğini ölçer.

Önceki derste `7` sabitinden çıkarılan tipin `Int` olduğunu gördük. Şimdi temel tiplere bakıyoruz: tam sayı için `Int` ve `Long`, kayan noktalı sayı için `Double`, tek karakter için `Char`, mantıksal değer için `Boolean`. Bu tiplerde eşitlik sorusunun iki yüzü var. Birincisi, farklı tipteki sayılar `==` ile karşılaştırılabilir mi? İkincisi, bir sayı kutulandığında (boxing) aynı değer iki nesneye bölünebilir mi?

## Tipler ve Açık Dönüşüm

Kotlin'de tam sayı sabiti varsayılan olarak `Int` olur. `Int` sınırını aşan sabit kendiliğinden `Long` olur; `L` soneki küçük bir değeri de `Long` yapmak için yazılır. Ondalıklı sabit `Double` olur. `Char` tek tırnakla yazılır ve sayısal kodunu `.code` ile verir. Dönüşümler açıktır: `Int` bir `Long` değişkene kendiliğinden atanmaz; `count.toLong()` yazılır. Aritmetik ise tipleri karıştırabilir: `Int` ile `Double` toplanınca sonuç `Double` olur.

Bu derste de ölçümler ilk derste tanıtılan yardımcı dosyayla yapılır. `Criterion` sınıfı, bir değer ile ikizini ve farklı bir değeri alıp üç soruyu sorar; dosya aşağıda aynen verilmiştir.

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

Aşağıdaki program bu kuralların hepsini bir arada çalıştırır. `total` değişkeni `Int` değerini `Long`'a çevirip milyarla çarpar. `7 / 2` ile `7 / 2.0` iki bölmeyi karşılaştırır: ilkinde iki taraf tam sayıdır, ikincisinde bir taraf ondalıklıdır. `letter + 1` bir `Char` ile bir sayıyı toplar.

```kotlin
// Main.kt — sayilar, karakter, mantiksal deger ve acik donusum
fun main() {
    val count: Int = 3
    val total: Long = count.toLong() * 1_000_000_000L
    val size = 2.5
    val letter = 'K'
    val ready = count > 2
    println(count + size)
    println(total)
    println(7 / 2)
    println(7 / 2.0)
    println(letter.code)
    println(letter + 1)
    println(ready)
}
```

```
5.5
3000000000
3
3.5
75
L
true
```

`count + size` 5.5 verir: `Int` ile `Double` toplandı ve sonuç `Double` oldu. `total` 3000000000 basar; bu değer `Int` sınırını aştığı için `Long` gerekti. `7 / 2` üç verir, çünkü iki taraf tam sayıdır ve bölme sayı bölmesi olarak yapılır, kesirli kısım atılır. `7 / 2.0` ise 3.5 verir. `letter.code` büyük `K` harfinin kodu olan 75'i basar. `letter + 1` bir sonraki karakter olan `L` harfini verir. Son satır `ready` değişkeninin `true` olduğunu gösterir.

**DT16.** Bu bölümde bölme `7` ve `2` sabitleriyle ölçüldü; negatif sayıda bölmenin davranışı ayrı bir bölümde ölçülür.

**DT17.** `Char` aritmetiği yalnız `letter + 1` ile ölçüldü; iki `Char` arasındaki farkın tipi bu derste ölçülmedi.

## Dönüşüm Açıktır, Karşılaştırma da

Aritmetiğin tipleri karıştırabilmesi atama ve karşılaştırma için geçerli değildir. `Int` değerini `Long` tipli bir değişkene atamak derleyicide reddedilir; bunu sandbox'ta derleyerek gördük, parça bu yüzden çıktısızdır.

```kotlin
val count: Int = 3
val wide: Long = count
```

Derleyici `Long` beklenen yerde `Int` bulduğunu bildirir. Karşılaştırma da aynı kuralı izler: bir `Int` ile bir `Long` sabitini `==` ile karşılaştırmak yine derlenmez.

```kotlin
val count: Int = 1
println(count == 1L)
```

Derleyici `==` işlecinin `Int` ile `Long` arasında uygulanamayacağını bildirir. Çözüm dönüşümü açık yazmaktır: `count.toLong() == 1L`. Ama tipler `Any` olarak tutulursa durum değişir: derleyici statik tipi bilemez, eşitliği çalışma anındaki nesnelere sorar.

```kotlin
// Main.kt — Any olarak tutulan sayilar
fun main() {
    val a: Any = 1
    val b: Any = 1L
    println(a == b)
}
```

```
false
```

`1` ile `1L`, `Any` olarak tutulduğunda eşit çıkmadı: çıktı `false`. Bir `Int` nesnesi ile bir `Long` nesnesi, sayısal değerleri aynı olsa da farklı sınıfa aittir ve `equals` bu farkı gözetir. Yani derleyicinin reddettiği karşılaştırma, tipi gizlendiğinde reddedilmez ama yine de yanıtı `false` olur.

**DT18.** Derleyici hataları Kotlin 2.4.21 ile alındı; ileri sürümlerde mesaj sözcükleri değişebilir, ama iki karşılaştırmanın reddedileceği kuralı bu derste ölçülen budur.

## Kutulanan Sayı ve NaN

Dersin ölçümü iki şeye bakar. Birincisi, boş değer alabilen bir tip olan `Int?` kutulanmış bir sayı tutar; JVM'de bu bir `Integer` nesnesidir. İki kutulanmış sayı aynı değerde olsa bile aynı nesne mi? İkincisi, `Double.NaN` (sayı olmayan değer) statik tipe göre farklı eşitlik verir. Önce iki tarafı da `Double` olan karşılaştırma, sonra aynı değerin `Any` olarak tutulduğu karşılaştırma yazdırılır.

```kotlin
// Main.kt — kutulanan sayilar ve NaN
fun main() {
    val boxedBig: Int? = 1000
    val boxedBigTwin: Int? = 1000
    val boxedSmall: Int? = 127
    val boxedSmallTwin: Int? = 127
    val nan = Double.NaN
    val anyNan: Any = nan
    val anyNanTwin: Any = Double.NaN
    println(nan == nan)
    println(anyNan == anyNan)
    val checks = listOf(
        Criterion("kutulanan-1000", boxedBig, boxedBigTwin, 1001),
        Criterion("kutulanan-127", boxedSmall, boxedSmallTwin, 128),
        Criterion("nan-any-tipinde", anyNan, anyNanTwin, 1.0),
    )
    for (check in checks) {
        check.report()
    }
    summarize(checks)
}
```

```
false
true
kutulanan-1000: ayni-nesne=false, ikiz=true, farkli=false -> icerik
kutulanan-127: ayni-nesne=true, ikiz=true, farkli=false -> tekil
nan-any-tipinde: ayni-nesne=false, ikiz=true, farkli=false -> icerik
tekil: 1
kimlik: 0
icerik: 2
kismi-icerik: 0
```

İlk iki satır NaN eşitliğidir. `nan == nan`, statik tip `Double` olduğu için IEEE kuralını izler ve `false` verir; NaN kendisine eşit değildir. `anyNan == anyNan` ise `true` verir, çünkü statik tip `Any` olduğunda `==` nesnenin `equals` yöntemini çağırır ve `equals` NaN'ı kendisine eşit sayar. Aynı sayı, hangi tipte tutulduğuna göre iki ayrı yanıt veriyor.

Üç ölçüm satırında `kutulanan-1000` içeriktir: iki `Int?` değişkeni 1000 değerinde ama ayrı nesnelerdir, `ayni-nesne=false`. `kutulanan-127` ise tekildir: aynı değer JVM'de aynı nesneye işaret eder, `ayni-nesne=true`. Tipi aynı, değer biçimi aynı iki sayı, değere göre farklı ölçüte düştü. `nan-any-tipinde` içeriktir: ikizle `==` `true` verir, ayrı nesnelerdir.

**DT19.** 127 ve 1000 JVM'de, Kotlin 2.4.21'de ölçüldü; hangi değerlerin paylaşıldığına dair genel bir sınır bu derste çıkarılmıyor ve 127 ile 1000 dışındaki değerler için bir iddia kurulmuyor.

**DT20.** NaN gözlemi tek bir `Double.NaN` değeriyle ve `Any` tipli tutarak ölçüldü; `Float.NaN` için aynı sonucun çıkması bu derste ölçülmedi.

## Taşma, Sıfıra Bölme ve Ondalık Hata

Tipin bir sınırı olması, sınırın aşıldığı durumda ne olacağını da bilmeyi gerektirir. Aşağıdaki blok üç sınır durumunu bir arada gösterir: `Int` sınırını aşan toplam, sıfıra tam sayı bölmesi ve sıfıra ondalıklı bölme. Ardından ondalıklı sayıların ikilik gösterimden gelen hatasını `0.1 + 0.2` ile sınar. Taşmayı hata olarak yakalayan `Math.addExact` çağrısı JVM'in kendi yöntemidir; Kotlin onu doğrudan çağırabilir.

```kotlin
// Main.kt — tasma, sifira bolme ve ondalik hata
fun main() {
    val zero = 0
    val big = 3_000_000_000
    println(Int.MAX_VALUE + 1)
    println(Long.MAX_VALUE)
    println(big::class.simpleName)
    try {
        Math.addExact(Int.MAX_VALUE, 1)
    } catch (e: ArithmeticException) {
        println(e.message)
    }
    try {
        println(1 / zero)
    } catch (e: ArithmeticException) {
        println(e.message)
    }
    println(1.0 / 0.0)
    println(0.1 + 0.2)
    println(0.1 + 0.2 == 0.3)
}
```

```
-2147483648
9223372036854775807
Long
integer overflow
/ by zero
Infinity
0.30000000000000004
false
```

`Int.MAX_VALUE + 1` hata vermez, sessizce `-2147483648` olur: sayı en büyük değerden en küçüğe sarar. `Long.MAX_VALUE` için `9223372036854775807` basılır. `3_000_000_000` sabiti `Int` sınırını aştığı için tip çıkarımı onu kendiliğinden `Long` yapar; çıktıdaki `Long` bunu doğrular. `Math.addExact` ise aynı toplamda `integer overflow` iletisiyle hata fırlatır; yani taşmanın fark edilmesini istiyorsanız bu yolu seçersiniz.

Tam sayı sıfıra bölününce `/ by zero` iletisi gelir. Ondalıklı bölmede aynı işlem hata vermez ve `Infinity` döner. Son iki satır ondalıklı sayının sınırını gösterir: `0.1 + 0.2` sonucu `0.30000000000000004` olur ve `0.3` ile `==` karşılaştırması `false` verir.

Sık yapılan hata iki yerde çıkar. Birincisi, taşmanın hata vermeyeceğini unutup toplamı `Int` içinde biriktirmektir. İkincisi, ondalıklı iki sayıyı `==` ile karşılaştırmaktır; para gibi tam çıkması gereken değerlerde ondalıklı tip yanlış seçimdir. Java karşılaştırması: bu çıktılar Java ile aynıdır, çünkü Kotlin burada JVM'in kendi aritmetiğini kullanır; Kotlin bu davranış için ayrı bir tip yazmayı gerektirmez. Bu aynılık Java kodu çalıştırılarak değil, çalışma ortamının aynı olmasına dayanarak söyleniyor.

**DT21.** Taşma `Int` toplamıyla, sıfıra bölme `Int` ve `Double` ile ölçüldü; `Long` taşması ve `Float` için sonucun aynı biçimde çıktığı bu derste ölçülmedi.

## Daraltan Dönüşümler

Genişleten dönüşüm sorun çıkarmaz; sorun değerin dar bir tipe sığdırıldığı yerde çıkar. Aşağıdaki blok beş dönüşümü ve metinden sayıya çevirmeyi ölçer: `300` değerini `Byte`a, ondalıklı sayıları `Int`e, `65` değerini `Char`a çevirmek ve geçerli ya da geçersiz bir dizgiyi `Int`e çevirmek.

```kotlin
// Main.kt — daraltan donusumler ve metinden sayi
fun main() {
    println(300.toByte())
    println(3.99.toInt())
    println((-3.99).toInt())
    println(65.toChar())
    println("42".toInt() + 1)
    println("x".toIntOrNull())
    try {
        "x".toInt()
    } catch (e: NumberFormatException) {
        println(e.message)
    }
}
```

```
44
3
-3
A
43
null
For input string: "x"
```

`300.toByte()` sekiz bitten fazlasını taşıyamaz ve `44` olur: yalnız alt sekiz bit kalır, üst bitler atılır ve hata verilmez. `3.99.toInt()` yuvarlamaz, kesirli kısmı keser; `3` çıkar. Negatif değerde `(-3.99).toInt()` de `-3` olur, yani sıfıra doğru kesme vardır, aşağı yuvarlama değil. `65.toChar()` büyük `A` harfini verir; sayı ile karakter kodu arasındaki köprü açıktır.

Metinden sayı çevirmenin iki yolu vardır. `"42".toInt() + 1` geçerli metinde `43` verir. Geçersiz metinde ise iki seçenek ayrılır: `toIntOrNull()` hata fırlatmak yerine `null` döndürür, `toInt()` ise `For input string: "x"` iletisiyle bir `NumberFormatException` fırlatır. Kullanıcıdan gelen metin için ilk yol bir `null` denetimi ister ama programı düşürmez, ikinci yol ise düşürür.

Mekanizmanın nedeni dönüşümlerin açık yazılmasıdır. Derleyici dar bir tipe sessizce atama yapmaz; `toByte()` yazmak, bilgi kaybını bilerek kabul ettiğini söyler. Java'da aynı daralma `(byte) 300` biçimindeki dönüştürme (cast) ile yazılır ve çoğu zaman gözden kaçar.

**DT22.** Dönüşümler `Byte`, `Int` ve `Char` ile ölçüldü; `Short`, `Float` ve `Long` için aynı kesme kurallarının geçerli olduğu bu derste ölçülmedi.

## Negatif Sayıda Bölme ve Mod

İlk bölümde `7 / 2` ifadesinin kesirli kısmı attığını gördük. Peki bölünen negatifse? Aşağıdaki blok negatif bir bölme ve kalan işleminin dört yazılışını, ardından üç başka sınır durumunu bir arada gösterir: en küçük `Int`in mutlak değeri, onaltılık ve ikilik sabit yazımı, iki `Char` arasındaki sıralama.

```kotlin
// Main.kt — negatif sayilarda bolme ve mod
import kotlin.math.abs

fun main() {
    println(-7 / 2)
    println(-7 % 2)
    println((-7).mod(2))
    println(Math.floorMod(-7, 2))
    println(abs(Int.MIN_VALUE))
    println(0xFF)
    println(0b1010)
    println('a' < 'b')
}
```

```
-3
-1
1
1
-2147483648
255
10
true
```

`-7 / 2` sonucu `-3` verir; kesirli kısım sıfıra doğru atılır, aşağıya doğru değil. `-7 % 2` ise `-1` verir: kalanın işareti bölünenin işaretini izler. Kalanın her zaman sıfır ya da pozitif çıkmasını istiyorsanız `(-7).mod(2)` ya da JVM'in `Math.floorMod(-7, 2)` çağrısı gerekir; ikisi de `1` verdi. Sık yapılan hata, bir dizinin indeksini `%` ile dönüştürürken negatif kalanın çıkabileceğini unutmaktır.

`abs(Int.MIN_VALUE)` sonucu `-2147483648` olur; mutlak değer bile pozitif çıkmaz, çünkü `Int` içinde `+2147483648` karşılığı yoktur. `0xFF` sabiti `255`, `0b1010` sabiti `10` basılır; onaltılık ve ikilik sabit yazımı tipin kendisini değiştirmez, yalnız yazılışı değiştirir. `'a' < 'b'` ifadesi `true` verir, çünkü `Char` değerleri karakter koduna göre sıralanır.

Java karşılaştırması: `%` işleci Java'da da bölünenin işaretini izler. Kotlin'in eklediği `mod`, Java'da `Math.floorMod` ile elde edilen sonucu işlecin yanında bir yöntem olarak sunar. Bu iki sonuç da yukarıdaki çıktıda gözlendi.

**DT23.** Negatif bölme ve kalan tek bir çiftle (`-7`, `2`) ölçüldü; negatif bölen ya da `Long` tipi için aynı işaret kuralının geçerli olduğu bu derste ölçülmedi.

## Ölçümlerden Çıkan Alışkanlıklar

Sayısal tiplerde Kotlin'in güvenceleri sınırlıdır ve bu dersin ölçümleri sınırın nerede başladığını gösterdi. Taşma sessizdir: `Int.MAX_VALUE + 1` çıktısı `-2147483648` oldu ve hiçbir istisna fırlatılmadı. Bu davranış Java ile aynıdır. Taşmanın zararlı olabileceği yerlerde, örneğin para hesabında ya da süre toplamında, `Long` kullanmak ya da `Math.addExact` gibi denetimli işlemler yazmak gerekir. `Long` için aynı taşma çok daha uzak bir sınırda olduğundan çoğu durumda yeterlidir, ama sınırı ortadan kaldırmaz.

Sıfıra bölme tam sayıda istisna fırlatır (`/ by zero`), ondalık sayıda ise `Infinity` verir. Bu fark, bir hesabın tipi değiştirildiğinde hata davranışının da değiştiği anlamına gelir. `Double` kullanan bir kod parçası sıfıra bölündüğünde sessizce çalışmaya devam eder ve sonucu yayar; hatayı fark etmek için `isInfinite` ya da `isNaN` denetimi gerekir. Ondalık sayılar ikili tabanda tutulduğu için `0.1 + 0.2` çıktısı `0.30000000000000004` oldu ve `== 0.3` karşılaştırması `false` verdi. Para gibi tam değer isteyen yerlerde `BigDecimal` ya da kuruşa çevrilmiş tam sayı kullanılır.

Daraltan dönüşümler de dikkat ister. Büyük bir tipten küçüğe çevirmek sayıyı kırpar ya da çevirir ve ölçümde `44`, `3`, `-3`, `A` gibi sonuçlar bunun her zaman "yuvarlama" olmadığını gösterdi: `toInt` ondalık kısmı atar, yani `-3.99` değeri `-3` olur. `toIntOrNull` ise çevrilemeyen dizgi için `null` döndürür, `toInt` aynı durumda istisna fırlatır ve `For input string: "x"` iletisi bu davranışı doğruladı. Kullanıcıdan gelen metni sayıya çevirirken `OrNull` biçimini seçmek, hatayı akışın bir parçası yapar.

Son olarak negatif bölme ve mod ölçümü, sonucun işaretinin Java ile aynı kuralı izlediğini gösterdi: bölme sıfıra doğru yuvarlanır, kalan ise bölünenin işaretini taşır. Matematikteki mod ile program mod işlemi aynı şey değildir; negatif sayılarla çalışan bir döngüsel indeks hesabında `mod` yerine `%` kullanan kod, indeksi eksiye çıkarabilir.

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

Kutulanan sayı için ölçüt değere bağlıdır: 1000 içerik, 127 tekil. Bu yüzden sayıların kimliğini `===` ile karşılaştırmak güvenilmez; sayı karşılaştırması `==` ile yapılır. Aynı değer 127 iken tekil, 1000 iken içerik çıktı. Tek bir ölçüt yerine iki ölçüt gördük.

NaN ise ayrı bir sınır koyar: statik tipi `Double` olan karşılaştırmada NaN eşit değildir, `Any` tipinde eşittir. `==` işlecinin anlamı, işlecin soldaki ifadenin statik tipine bağlı olduğu bir yerde değişir.

## Özet

- Tam sayı sabiti `Int` olur; sınırı aşan değer `Long` ister. Ondalıklı sabit `Double` olur.
- `Int` değeri `Long` değişkene kendiliğinden atanmaz ve bir `Int` ile bir `Long` sabiti `==` ile karşılaştırılamaz.
- Aritmetik tipleri karıştırabilir: `Int` ile `Double` toplamı `Double` olur.
- Boş değer alabilen `Int` kutulanır; 127 tekil, 1000 ise içerik çıktı.
- Bu dersin ölçütü: **içerik** (1000); sınırlayıcı ölçüm: 127 değeri JVM'de tekildir ve NaN statik tipe göre farklı eşitlik verir.

## Sonraki Adım

Sayıları ve karakteri gördük. Sıradaki derste dizgilere dönüyoruz: şablonlar, ham dizgiler ve `trimIndent`. Bir dizgiyi şablonla kurmak, aynı metni elle yazmakla aynı nesneyi mi verir, onu ölçeriz.
