Primitive (İlkel) Veri Tipleri
Java'da her şeyin bir tipi var. Bir değişken tanımlarken "bu değişken ne tür bir veri tutacak?" sorusuna cevap veriyorsun. İşte primitive tipler, Java'nın en temel yapı taşları — bellekte doğrudan değer saklayan, nesne olmayan tipler.
Bunu şöyle düşün: Bir depo kiralıyorsun. Küçük bir kutu mu istiyorsun, kocaman bir konteyner mı? Ne kadar yer ayırırsan o kadar ödüyorsun. Primitive tipler de tam olarak bu — her biri bellekte farklı büyüklükte yer kaplıyor.
Neden Primitive Tipler Var?
Java nesne yönelimli bir dil ama her şeyi nesne yapmak performans açısından maliyetli. Bir int değer bellekte sadece 4 byte yer kaplarken, onun nesne karşılığı Integer çok daha fazla yer kaplar ve ek yük getirir.
Bu yüzden Java, sık kullanılan temel veri türleri için "primitive" dediğimiz hafif tipler sunar. Toplam 8 tane var ve hepsini bilmen gerekiyor.
8 Primitive Tip — Büyük Tablo
Hepsini bir arada görelim, sonra tek tek inceleyeceğiz:
| Tip | Boyut | Varsayılan | Min Değer | Max Değer | Kullanım |
|---|---|---|---|---|---|
| byte | 1 byte | 0 | -128 | 127 | Küçük sayılar, dosya verileri |
| short | 2 byte | 0 | -32,768 | 32,767 | Orta küçük sayılar |
| int | 4 byte | 0 | -2,147,483,648 | 2,147,483,647 | Genel amaçlı tam sayı |
| long | 8 byte | 0L | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 | Çok büyük tam sayılar |
| float | 4 byte | 0.0f | ≈ ±1.4 × 10⁻⁴⁵ | ≈ ±3.4 × 10³⁸ | Ondalıklı (düşük hassasiyet) |
| double | 8 byte | 0.0d | ≈ ±4.9 × 10⁻³²⁴ | ≈ ±1.8 × 10³⁰⁸ | Ondalıklı (yüksek hassasiyet) |
| char | 2 byte | '\u0000' | 0 | 65,535 | Tek karakter (Unicode) |
| boolean | ~1 bit | false | false | true | Doğru/yanlış |
Tam Sayı Tipleri: byte, short, int, long
byte — Küçük Ama Öz
1 byte = 8 bit. -128 ile 127 arası değer tutar. Genellikle dosya okuma/yazma işlemlerinde veya ağ programlamada karşılaşırsın.
byte yas = 25;
byte sicaklik = -10;
byte maxByte = 127;
// byte hata = 128; // HATA! byte max 127Günlük programlamada çok sık kullanmazsın ama dosya işlemlerinde (InputStream, OutputStream) sürekli karşına çıkar.
short — Nadiren Kullanılan Orta Boy
2 byte yer kaplar. -32,768 ile 32,767 arası. Dürüst olalım: pratikte neredeyse hiç kullanmayız. int zaten her yerde iş görüyor.
short population = 30000;
short altitude = -500;Eğer bellekten çok tasarruf etmen gereken büyük diziler varsa ve değerlerin bu aralıkta olduğunu biliyorsan short mantıklı olabilir. Ama çoğu zaman int kullan, hayatını kolaylaştır.
int — Günlük Ekmek
4 byte. Yaklaşık ±2.1 milyar aralık. Java'da tam sayı deyince akla ilk gelen tip bu. Sayaçlar, indeksler, döngüler — hep int.
int nufus = 85000000;
int bakiye = -15000;
int max = Integer.MAX_VALUE; // 2,147,483,647
int min = Integer.MIN_VALUE; // -2,147,483,648
System.out.println("Max int: " + max);
System.out.println("Min int: " + min);💡 Java'da bir sayıyı yazarken (literal) varsayılan tip
int'tir. Yani42yazdığında Java bunuintolarak algılar.
long — Büyük İşler İçin
8 byte. Devasa sayılar için. Zaman damgaları (timestamp), dosya boyutları, büyük ID'ler — bunlar long ister.
long dunyaNufusu = 8000000000L; // Sonuna L koy!
long timestamp = System.currentTimeMillis();
long dosyaBoyutu = 5368709120L; // 5 GB in bytes
System.out.println("Şu anki zaman: " + timestamp);⚠️ Dikkat: long literal yazarken sonuna L veya l eklemelisin. Küçük l sayı 1 ile karışabilir, bu yüzden büyük L kullan.
// long hata = 8000000000; // HATA! int aralığını aşıyor
long dogru = 8000000000L; // Sonuna L koyunca long olurOndalıklı Sayı Tipleri: float, double
float — Yeterli Hassasiyet
4 byte, yaklaşık 6-7 basamak hassasiyet. Grafik programlama, oyun geliştirme gibi alanlarda bellek önemliyse kullanılır.
float pi = 3.14f; // Sonuna f koy!
float sicaklik = 36.6f;
float oran = 0.75f;
System.out.println("Pi: " + pi);⚠️ Dikkat: Java'da ondalıklı sayılar varsayılan olarak double'dır. float kullanmak istiyorsan sonuna f eklemelisin.
double — Varsayılan Ondalıklı
8 byte, yaklaşık 15-16 basamak hassasiyet. Ondalıklı sayı gerektiğinde çoğu zaman double kullanırsın.
double pi = 3.141592653589793;
double maasBrut = 45750.50;
double avogadro = 6.022e23; // Bilimsel notasyon
System.out.println("Pi detaylı: " + pi);
System.out.println("Avogadro: " + avogadro);float vs double — Hangisini Seçeyim?
Kısa cevap: double kullan. Daha hassas, modern donanımda performans farkı yok denecek kadar az.
float f = 0.1f + 0.2f;
double d = 0.1 + 0.2;
System.out.println("float: " + f); // 0.3
System.out.println("double: " + d); // 0.30000000000000004İkisi de tam doğru değil — bu ondalıklı sayıların doğasından kaynaklanan bir durum (IEEE 754). Ama double daha hassas olduğu için genellikle daha iyi sonuç verir.
💡 Para hesaplamalarında ne
floatnedoublekullan! Kuruş kaybedersin.BigDecimalsınıfını kullan — buna ileride değineceğiz.
Karakter Tipi: char
2 byte. Tek bir Unicode karakteri tutar. Tek tırnak (') ile yazılır.
char harf = 'A';
char rakam = '7';
char turkce = 'Ş';
char emoji = '♥';
char unicode = '\u0041'; // 'A' nin Unicode karşılığı
System.out.println(harf); // A
System.out.println(unicode); // Achar aslında sayısal bir tiptir — 0 ile 65,535 arası bir tam sayı tutar. Bu sayı, Unicode tablosundaki karakterin numarasıdır.
char c = 'A';
int sayisal = c;
System.out.println(sayisal); // 65
char d = 66;
System.out.println(d); // BDikkat: char ile String farklı şeyler. char tek karakter, String karakter dizisi. char primitive, String nesne.
char c = 'A'; // Tek tırnak — char
String s = "A"; // Çift tırnak — String
// Bunlar aynı şey değil!Mantıksal Tip: boolean
Sadece true veya false değeri alır. Koşullarda, kontrollerde, bayrak (flag) olarak kullanılır.
boolean aktif = true;
boolean ogrenci = false;
boolean yetiskin = (yas >= 18);
if (aktif) {
System.out.println("Kullanıcı aktif");
}Bellekte kaç byte kapladığı JVM implementasyonuna bağlı. Spesifikasyon "1 bit bilgi" diyor ama pratikte genellikle 1 byte kullanılır.
boolean sonuc = (10 > 5); // true
boolean esit = (3 == 4); // false
boolean degil = !true; // false
System.out.println(sonuc); // true
System.out.println(esit); // false
System.out.println(degil); // falseVarsayılan Değerler
Bir sınıfın alanı (field) olarak tanımlanan primitive değişkenlere otomatik varsayılan değer atanır:
public class VarsayilanDegerler {
byte b; // 0
short s; // 0
int i; // 0
long l; // 0L
float f; // 0.0f
double d; // 0.0d
char c; // '\u0000' (null karakter)
boolean bo; // false
void yazdir() {
System.out.println("byte: " + b);
System.out.println("int: " + i);
System.out.println("boolean: " + bo);
System.out.println("char: [" + c + "]");
}
}⚠️ Ama lokal değişkenlere varsayılan değer atanmaz! Metot içinde tanımladığın bir değişkeni kullanmadan önce mutlaka değer atamalısın, yoksa derleme hatası alırsın.
void metot() {
int x;
// System.out.println(x); // DERLEME HATASI!
int y = 0; // Bu doğru
System.out.println(y); // OK
}Ne Zaman Hangisini Kullanmalı?
İşte pratik bir rehber:
| Senaryo | Kullan |
|---|---|
| Genel amaçlı tam sayı | int |
| Döngü sayacı | int |
| Dizi indeksi | int |
| Zaman damgası, büyük ID | long |
| Dosya boyutu | long |
| Ondalıklı sayı (genel) | double |
| Koşul, bayrak | boolean |
| Tek karakter | char |
| Dosya/ağ byte verileri | byte |
| Bellek hassas, büyük diziler | short veya byte |
| Oyun/grafik, bellek kritik | float |
Şüpheye düştüğünde: tam sayı için int, ondalık için double, mantıksal için boolean. Bu üçlü seni çoğu durumda kurtarır.
Literal Gösterimler
Java'da sayıları farklı formatlarda yazabilirsin:
// Tam sayı literalleri
int onluk = 42;
int ikilik = 0b101010; // Binary (0b prefix)
int sekizlik = 052; // Octal (0 prefix)
int onaltilik = 0x2A; // Hex (0x prefix)
System.out.println(onluk); // 42
System.out.println(ikilik); // 42
System.out.println(sekizlik); // 42
System.out.println(onaltilik); // 42Java 7'den itibaren okunabilirlik için alt çizgi kullanabilirsin:
int milyon = 1_000_000;
long krediKartiNo = 1234_5678_9012_3456L;
double pi = 3.14_15_92;
System.out.println(milyon); // 1000000Alt çizgiler derleme sırasında yok sayılır, sadece senin okumanı kolaylaştırır. Büyük sayılarda çok işe yarar.
Literal Kısıtlamaları
Alt çizginin nereye koyabileceğin konusunda kurallar var:
// Geçerli
int a = 1_000_000;
int b = 0xFF_EC_DE;
int c = 0b1010_1010;
// Geçersiz — derleme hatası
// int d = _1000; // Başında
// int e = 1000_; // Sonunda
// float f = 3._14f; // Noktanın yanında
// int g = 0_x1A; // Prefix'in içinde
// long h = 123_L; // L suffix'in yanındaBellekte Nasıl Saklanıyor?
Primitive tipler stack bellek alanında saklanır. Bu onları çok hızlı yapar.
int a = 5;
int b = a; // a'nın DEĞERİ kopyalanır
b = 10;
System.out.println(a); // 5 — a değişmedi!
System.out.println(b); // 10Primitive'lerde bir değişkeni diğerine atadığında değer kopyalanır. İki değişken birbirinden bağımsızdır. Bu, nesnelerden (referans tipleri) farklıdır — nesnelerde adres kopyalanır, bu yüzden biri değişince diğeri de etkilenebilir. Bu farkı ileride detaylı göreceğiz.
Pratik Örnek: Basit Hesap Makinesi Değişkenleri
public class HesapMakinesi {
public static void main(String[] args) {
int sayi1 = 100;
int sayi2 = 45;
double sonuc;
sonuc = sayi1 + sayi2;
System.out.println("Toplam: " + sonuc); // 145.0
sonuc = (double) sayi1 / sayi2;
System.out.println("Bölüm: " + sonuc); // 2.2222...
boolean pozitif = (sonuc > 0);
System.out.println("Pozitif mi? " + pozitif); // true
char islem = '+';
System.out.println("İşlem: " + islem); // +
}
}Bu küçük örnekte int, double, boolean ve char — dört farklı primitive tipi bir arada kullandık. Gerçek projelerde de durum çoğunlukla böyle: birden fazla tip bir arada çalışır.
Primitive Tipler vs Referans Tipler
Java'da iki kategori veri tipi var: primitive ve referans. Bu farkı anlamak çok önemli çünkü davranışları tamamen farklı.
| Özellik | Primitive | Referans (Nesne) |
|---|---|---|
| Bellekte | Stack'te değer | Stack'te adres, heap'te nesne |
| Varsayılan | 0, false, '\u0000' | null |
| null olabilir mi? | Hayır | Evet |
| Metot çağrılabilir mi? | Hayır | Evet |
| == ne yapar? | Değer karşılaştırır | Adres karşılaştırır |
// Primitive — değer kopyalanır
int x = 10;
int y = x;
y = 20;
System.out.println(x); // 10 — x değişmedi
// Referans — adres kopyalanır
int[] dizi1 = {1, 2, 3};
int[] dizi2 = dizi1; // Aynı diziyi gösteriyor!
dizi2[0] = 99;
System.out.println(dizi1[0]); // 99 — dizi1 de değişti!Bu fark özellikle metotlara parametre geçerken çok önemli hale gelir. Primitive geçtiğinde kopya gider — metot orijinali değiştiremez. Referans geçtiğinde adres gider — metot nesneyi değiştirebilir.
public static void artir(int sayi) {
sayi++; // Kopya üzerinde çalışır
}
public static void main(String[] args) {
int a = 5;
artir(a);
System.out.println(a); // 5 — değişmedi!
}İkiye Tümleyen (Two's Complement)
Java'da negatif tam sayılar ikiye tümleyen (two's complement) yöntemiyle saklanır. Bu konuyu derinlemesine bilmek gerekmez ama temel mantığını anlamak bazı tuzaklardan kurtarır.
Bir byte için:
Pozitif sayılar normal ikili:
5=00000101Negatif sayılar: tüm bitleri tersle, 1 ekle
- 5 = 00000101 → tersle: 11111010 → +1: 11111011 = -5
En soldaki bit (MSB) işaret biti: 0 = pozitif, 1 = negatif
byte b = 127; // 01111111
b++; // 10000000 = -128 (taşma!)
System.out.println(b); // -128
// Bu yüzden byte aralığı -128 ile 127
// 0 pozitif tarafta sayılır: 0..127 = 128 değer, -128..-1 = 128 değerBu, overflow'un neden "döndüğünü" açıklar. Max değerden bir fazlası, en küçük negatif sayıya denk gelir.
Tip Promosyonu (Type Promotion)
Farklı tipler bir arada kullanıldığında Java otomatik olarak küçük tipi büyüğe çevirir. Buna tip promosyonu denir.
byte a = 10;
byte b = 20;
// byte c = a + b; // HATA! a + b sonucu int'tir
int c = a + b; // Doğru
short s = 100;
int i = 200;
long l = s + i; // short + int = int, int → long
float f = 3.14f;
double d = f + 1; // float + int = float, float → doublePromosyon kuralları:
byte,short,char→ aritmetik işlemdeint'e yükseltilirOperandlardan biri
longise diğeri delongolurOperandlardan biri
floatise diğeri defloatolurOperandlardan biri
doubleise diğeri dedoubleolur
char c = 'A'; // 65
int sonuc = c + 1; // 66 — char + int = int
System.out.println(sonuc); // 66
System.out.println((char) sonuc); // BBu konu Type Casting dersinde çok daha detaylı işlenecek.
Wrapper Sınıflarla Karşılaştırma
Her primitive tipin bir nesne karşılığı (wrapper class) var. İleride detaylı göreceğiz ama temel farkı şimdi bilelim:
int primitiveInt = 42; // Primitive — stack'te
Integer wrapperInt = 42; // Nesne — heap'te (autoboxing)
// Primitive null olamaz
// int x = null; // DERLEME HATASI!
// Wrapper null olabilir
Integer y = null; // OK
// int z = y; // NullPointerException! (unboxing)| Primitive | Wrapper |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
Koleksiyonlar (List, Map vb.) primitive alamaz, wrapper gerekir:
List<Integer> sayilar = new ArrayList<>(); // int değil, Integer
sayilar.add(42); // Autoboxing: int → IntegerGerçek Proje Senaryoları
Senaryo 1: Veritabanı ID'leri
// Veritabanı ID'leri genellikle long
long kullaniciId = 1234567890L;
long siparisId = 9876543210L;
// Neden int değil? Çünkü popüler uygulamalarda
// int'in 2.1 milyar sınırı kolayca aşılabilir
// Twitter'ın tweet ID'leri long — trilyonlara ulaştıSenaryo 2: Dosya İşlemleri
// Dosya boyutunu byte olarak okuma
byte[] buffer = new byte[1024]; // 1KB buffer
// InputStream.read() byte dizisi kullanır
// Dosya boyutu long
long boyut = new java.io.File("video.mp4").length();
System.out.println("Dosya: " + (boyut / 1024 / 1024) + " MB");Senaryo 3: Oyun Geliştirme
// Oyunda konum — float yeterli, bellek tasarrufu
float oyuncuX = 150.5f;
float oyuncuY = 320.8f;
boolean zipliyor = false;
int can = 3;
char seviye = 'A'; // Seviye göstergesi
// Her frame'de güncelleme
oyuncuX += 2.5f;
if (zipliyor) {
oyuncuY -= 5.0f;
}Senaryo 4: Sensör Verileri
// IoT cihazından gelen sıcaklık — double hassasiyet
double sicaklik = 23.456789;
double nem = 65.2;
boolean alarmAktif = sicaklik > 40.0;
// Sensör ID — short yeterli (max 32767 sensör)
short sensorId = 1042;
byte pil = 87; // Pil yüzdesi (0-100)Min/Max Değerleri Programla Öğrenme
Her primitive tipin sınırlarını Java'nın kendisinden öğrenebilirsin:
System.out.println("byte : " + Byte.MIN_VALUE + " ~ " + Byte.MAX_VALUE);
System.out.println("short : " + Short.MIN_VALUE + " ~ " + Short.MAX_VALUE);
System.out.println("int : " + Integer.MIN_VALUE + " ~ " + Integer.MAX_VALUE);
System.out.println("long : " + Long.MIN_VALUE + " ~ " + Long.MAX_VALUE);
System.out.println("float : " + Float.MIN_VALUE + " ~ " + Float.MAX_VALUE);
System.out.println("double: " + Double.MIN_VALUE + " ~ " + Double.MAX_VALUE);
// Boyutları byte cinsinden
System.out.println("int boyutu: " + Integer.BYTES + " byte");
System.out.println("long boyutu: " + Long.BYTES + " byte");
System.out.println("double boyutu: " + Double.BYTES + " byte");
// Özel double değerler
System.out.println("Pozitif sonsuz: " + Double.POSITIVE_INFINITY);
System.out.println("Negatif sonsuz: " + Double.NEGATIVE_INFINITY);
System.out.println("Sayı değil: " + Double.NaN);Sık Yapılan Hatalar
1. Aralık dışına çıkmak:
byte b = 130; // HATA! byte max 1272. Long literal'de L unutmak:
long x = 3000000000; // HATA! int aralığını aşıyor
long y = 3000000000L; // Doğru3. Float literal'de f unutmak:
float f = 3.14; // HATA! 3.14 double, float'a sığmaz
float g = 3.14f; // Doğru4. Lokal değişkeni initialize etmeden kullanmak:
int x;
System.out.println(x); // DERLEME HATASI!5. boolean'a 0 veya 1 atamak:
boolean b = 1; // HATA! Java'da boolean sadece true/false
boolean c = true; // DoğruC/C++ alışkanlığı olan arkadaşlar bu hatayı sık yapar. Java'da 0 false değildir, 1 true değildir. boolean sadece true ve false kabul eder, nokta.
6. byte ve short ile aritmetik yaparken tip promosyonunu unutmak:
byte a = 10;
byte b = 20;
byte c = a + b; // HATA! Sonuç int'tir
byte d = (byte)(a + b); // Doğru, explicit cast7. Ondalıklı sayıları == ile karşılaştırmak:
double a = 0.1 + 0.2;
System.out.println(a == 0.3); // false! IEEE 754 hassasiyet sorunuPerformans İpuçları
Primitive tipler bellek ve performans açısından wrapper'lardan çok daha verimli:
// Bellek karşılaştırması (yaklaşık)
// int → 4 byte
// Integer → 16 byte (nesne overhead) + 4 byte (değer) = ~20 byte
// 1 milyon int dizisi
int[] primitiveArray = new int[1_000_000];
// Bellek: ~4 MB
// 1 milyon Integer dizisi
Integer[] wrapperArray = new Integer[1_000_000];
// Bellek: ~20 MB (5 kat fazla!)// Performans farkı
long baslangic = System.nanoTime();
// Primitive ile toplama
long toplam1 = 0L;
for (int i = 0; i < 10_000_000; i++) {
toplam1 += i;
}
long sure1 = System.nanoTime() - baslangic;
baslangic = System.nanoTime();
// Wrapper ile toplama (autoboxing/unboxing)
Long toplam2 = 0L;
for (int i = 0; i < 10_000_000; i++) {
toplam2 += i; // Her adımda unbox → topla → autobox
}
long sure2 = System.nanoTime() - baslangic;
System.out.printf("Primitive: %d ms%n", sure1 / 1_000_000);
System.out.printf("Wrapper : %d ms%n", sure2 / 1_000_000);
// Wrapper tipik olarak 5-10x daha yavaşMülakat Soruları — Bunları Bilmeni Beklerler
Teknik mülakata girdiğinde primitive tiplerle ilgili şu sorular sıkça sorulur:
S: Java'da kaç primitive tip var? C: 8 — byte, short, int, long, float, double, char, boolean.
S: String primitive midir? C: Hayır, String bir sınıftır (referans tipi). Ama Java onu özel olarak destekler (literal kullanımı, + operatörü vb.).
S: char kaç byte? C: 2 byte. Java UTF-16 kullandığı için 1 byte değil.
S: boolean kaç byte? C: JVM spesifikasyonu bunu tanımlamaz. Pratikte genellikle 1 byte ama implementasyona bağlı.
S: int ile Integer farkı nedir? C: int primitive, stack'te saklanır, null olamaz. Integer nesne (wrapper), heap'te saklanır, null olabilir, koleksiyonlarda kullanılır.
Özet
Java'da 8 primitive tip vardır:
byte,short,int,long,float,double,char,booleanTam sayılar için çoğunlukla `int` yeterlidir; büyük sayılar için `long` kullan
Ondalıklı sayılar için `double` varsayılan ve en güvenli seçimdir
longliteral sonuna `L`,floatliteral sonuna `f` eklemeyi unutmaSınıf alanları varsayılan değer alır ama lokal değişkenler almaz — mutlaka initialize et
Primitive tipler stack'te saklanır ve atamada değer kopyalanır (referans değil)
AI Asistan
Sorularını yanıtlamaya hazır