Method Overloading
Giriş — Aynı İsim, Farklı Parametre
Diyelim ki bir topla metodu yazdın. İki int topluyorsun. Ama sonra üç int toplamak istedin. Bir de double toplamak istedin. Her birine farklı isim mi vereceksin? toplaIkiInt, toplaUcInt, toplaDouble?
Hayır! Java'da aynı isimli birden fazla metot tanımlayabilirsin — yeter ki parametreleri farklı olsun. Buna method overloading (metot aşırı yükleme) denir.
Analoji: "Aç" kelimesini düşün. "Kapıyı aç", "dosyayı aç", "şişeyi aç" — aynı fiil ama farklı nesnelere uygulanıyor ve her biri farklı bir eylem. Java'da da topla(int, int) ve topla(double, double) aynı isim ama farklı işlem.
Overloading Temelleri
Overloading için metotların imzaları farklı olmalı. İmza = metot adı + parametre tipleri ve sırası.
public class Toplama {
// 2 int toplama
public static int topla(int a, int b) {
return a + b;
}
// 3 int toplama
public static int topla(int a, int b, int c) {
return a + b + c;
}
// 2 double toplama
public static double topla(double a, double b) {
return a + b;
}
public static void main(String[] args) {
System.out.println(topla(3, 5)); // 8 → topla(int, int)
System.out.println(topla(3, 5, 7)); // 15 → topla(int, int, int)
System.out.println(topla(3.5, 2.1)); // 5.6 → topla(double, double)
}
}Java, çağrıdaki argüman tiplerini ve sayısını bakarak hangi metodu çağıracağını otomatik belirler. Bu işlem derleme zamanında (compile-time) gerçekleşir.
Overloading İçin Yeterli Farklar
Parametre sayısı farklı → overload
Parametre tipleri farklı → overload
Parametre sırası farklı → overload (ama dikkatli ol!)
void metot(int a, String b) { } // metot(int, String)
void metot(String a, int b) { } // metot(String, int) — farklı imzaOverloading İçin Yetersiz Farklar
Sadece dönüş tipi farklı → overload OLMAZ
Sadece parametre isimleri farklı → overload OLMAZ
// DERLEME HATASI — sadece dönüş tipi farklı
int topla(int a, int b) { return a + b; }
double topla(int a, int b) { return a + b; } // Aynı imza!
// DERLEME HATASI — sadece parametre isimleri farklı
void yazdir(String mesaj) { }
void yazdir(String text) { } // Aynı imza: yazdir(String)💡 İpucu: Overloading, "aynı işi farklı tiplerle yapan" metotlar için kullan. Tamamen farklı işler yapan metotlara farklı isimler ver.
Overloading Örnekleri
Örnek: print/println
Java'nın kendi println metodu overloaded:
System.out.println(42); // println(int)
System.out.println(3.14); // println(double)
System.out.println("Merhaba"); // println(String)
System.out.println(true); // println(boolean)
System.out.println('A'); // println(char)Aynı isim, farklı tipler. Hepsini ayrı isimle çağırmak zorunda olsaydın: printlnInt, printlnDouble, printlnString... Korkunç olurdu.
Örnek: Geometrik Alan Hesaplama
public class AlanHesapla {
// Kare alanı
public static double alan(double kenar) {
return kenar * kenar;
}
// Dikdörtgen alanı
public static double alan(double en, double boy) {
return en * boy;
}
// Üçgen alanı
public static double alan(double taban, double yukseklik, boolean ucgenMi) {
return taban * yukseklik / 2;
}
public static void main(String[] args) {
System.out.println("Kare: " + alan(5)); // 25.0
System.out.println("Dikdörtgen: " + alan(5, 3)); // 15.0
System.out.println("Üçgen: " + alan(6, 4, true)); // 12.0
}
}Her alan() çağrısı parametre sayısına göre doğru metoda yönlendirilir.
Örnek: Formatlı Yazdırma
public static void bilgiYazdir(String isim) {
System.out.println("İsim: " + isim);
}
public static void bilgiYazdir(String isim, int yas) {
System.out.println("İsim: " + isim + ", Yaş: " + yas);
}
public static void bilgiYazdir(String isim, int yas, String sehir) {
System.out.println("İsim: " + isim + ", Yaş: " + yas + ", Şehir: " + sehir);
}
public static void main(String[] args) {
bilgiYazdir("Ali");
bilgiYazdir("Ayşe", 25);
bilgiYazdir("Mehmet", 30, "İstanbul");
}Overload Resolution — Java Nasıl Karar Veriyor?
Birden fazla overloaded metot varsa, Java en uygun olanını seçer. Bu sürece overload resolution denir.
1. Tam Eşleşme (Exact Match)
void metot(int x) { System.out.println("int"); }
void metot(double x) { System.out.println("double"); }
metot(5); // "int" — tam eşleşme
metot(5.0); // "double" — tam eşleşme2. Otomatik Genişleme (Widening)
Tam eşleşme yoksa Java, daha geniş bir tipe otomatik dönüşüm yapar:
void metot(double x) { System.out.println("double"); }
metot(5); // "double" — int → double genişlemeint → double otomatik genişleme (widening) yapılır çünkü veri kaybı olmaz.
Genişleme sırası:
byte → short → int → long → float → double
char → int → long → float → double3. Birden Fazla Uygun Metot — Ambiguity
void metot(int a, double b) { }
void metot(double a, int b) { }
metot(5, 5); // DERLEME HATASI — ambiguous!Java ikisi arasında karar veremez çünkü her iki metoda da dönüşüm gerekli. Bu durumda cast yaparak belirsizliği çözersin:
metot(5, (double) 5); // metot(int, double) çağrılır
metot((double) 5, 5); // metot(double, int) çağrılır4. Autoboxing ve Unboxing
Java 5+ ile primitive ↔ wrapper otomatik dönüşüm yapılır:
void metot(int x) { System.out.println("primitive int"); }
void metot(Integer x) { System.out.println("wrapper Integer"); }
metot(5); // "primitive int" — tam eşleşme öncelikli
metot(Integer.valueOf(5)); // "wrapper Integer"Tam eşleşme her zaman autoboxing'ten önceliklidir.
Öncelik Sırası
1. Tam eşleşme (exact match)
2. Genişleme (widening)
3. Autoboxing/Unboxing
4. Varargs (en son)⚠️ Dikkat: Bu kuralları ezberleme. Karmaşık overloading senaryolarında Java'nın ne yapacağını tahmin etmek zor olabilir. Şüphe duyduğunda cast yap veya farklı isim ver.
Varargs (Değişken Sayıda Argüman)
Ya 2, ya 5, ya 100 parametre göndermek istersen? Her biri için ayrı overload mu yazacaksın? Hayır — varargs (variable arguments) bunu çözer.
public static int topla(int... sayilar) {
int toplam = 0;
for (int s : sayilar) {
toplam += s;
}
return toplam;
}
public static void main(String[] args) {
System.out.println(topla()); // 0
System.out.println(topla(5)); // 5
System.out.println(topla(1, 2, 3)); // 6
System.out.println(topla(1, 2, 3, 4, 5)); // 15
}int... sayilar ifadesi, sıfır veya daha fazla int argüman kabul eder. Metot içinde sayilar bir dizi gibi davranır.
Varargs Kuralları
Her metotta en fazla bir varargs parametresi olabilir
Son parametre olmalı
// DOĞRU — varargs sonda
void metot(String mesaj, int... sayilar) { }
// YANLIŞ — varargs sonda değil
void metot(int... sayilar, String mesaj) { } // Derleme hatası!
// YANLIŞ — iki varargs
void metot(int... a, double... b) { } // Derleme hatası!Örnek: Loglamac
public static void log(String seviye, String... mesajlar) {
System.out.print("[" + seviye + "] ");
for (String mesaj : mesajlar) {
System.out.print(mesaj + " ");
}
System.out.println();
}
public static void main(String[] args) {
log("INFO", "Sistem başlatıldı");
log("ERROR", "Bağlantı", "hatası", "oluştu");
log("DEBUG", "x=5", "y=10", "z=15", "toplam=30");
}Varargs ve Dizi
Varargs aslında arka planda bir dizi oluşturur. Dizi de gönderebilirsin:
int[] notlar = {90, 85, 78};
// Her ikisi de çalışır:
topla(1, 2, 3); // varargs
topla(notlar); // diziVarargs ve Overloading
Varargs overloading'de en düşük önceliğe sahiptir:
void metot(int a, int b) { System.out.println("iki parametre"); }
void metot(int... a) { System.out.println("varargs"); }
metot(1, 2); // "iki parametre" — tam eşleşme öncelikli
metot(1, 2, 3); // "varargs" — sadece bu eşleşir
metot(1); // "varargs"💡 İpucu: Varargs kullanışlıdır ama aşırı kullanma. Eğer genellikle 2-3 parametreyle çağrılıyorsa, o sayılar için ayrı overload yaz ve varargs'ı "geri kalan" için tut. Bu hem okunabilirliği hem performansı artırır (varargs her çağrıda dizi oluşturur).
Overloading ve Constructors
Constructor'lar (yapıcı metotlar) da overloaded olabilir. Bu, nesneleri farklı şekillerde oluşturmayı sağlar. OOP dersinde detaylı göreceğiz ama kısa bir önizleme:
public class Dikdortgen {
double en, boy;
// Parametresiz — varsayılan değerler
public Dikdortgen() {
this.en = 1;
this.boy = 1;
}
// Kare — tek parametre
public Dikdortgen(double kenar) {
this.en = kenar;
this.boy = kenar;
}
// Dikdörtgen — iki parametre
public Dikdortgen(double en, double boy) {
this.en = en;
this.boy = boy;
}
}
// Kullanım
Dikdortgen d1 = new Dikdortgen(); // 1x1
Dikdortgen d2 = new Dikdortgen(5); // 5x5
Dikdortgen d3 = new Dikdortgen(5, 3); // 5x3Overloading vs Overriding
Bu iki kavram sık karıştırılır. Şimdilik kısa bir karşılaştırma yapalım (overriding'i OOP derslerinde göreceksin):
| Özellik | Overloading | Overriding |
|---|---|---|
| Aynı sınıfta mı? | Evet | Hayır (alt sınıfta) |
| Metot adı | Aynı | Aynı |
| Parametreler | Farklı olmalı | Aynı olmalı |
| Dönüş tipi | Farklı olabilir | Aynı (veya alt tip) |
| Bağlama zamanı | Derleme (compile-time) | Çalışma (runtime) |
| static? | Olabilir | Olamaz |
Overloading = "aynı isim, farklı parametreler, derleme zamanında çözülür" Overriding = "aynı metot, alt sınıfta yeniden tanımlanır, çalışma zamanında çözülür"
Pratik Örnek: String Formatlama Yardımcıları
public class StringUtil {
// Sola hizala
public static String padLeft(String metin, int uzunluk) {
return padLeft(metin, uzunluk, ' ');
}
// Sola hizala — özel karakter
public static String padLeft(String metin, int uzunluk, char dolgu) {
if (metin.length() >= uzunluk) return metin;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < uzunluk - metin.length(); i++) {
sb.append(dolgu);
}
sb.append(metin);
return sb.toString();
}
public static void main(String[] args) {
System.out.println(padLeft("42", 5)); // " 42"
System.out.println(padLeft("42", 5, '0')); // "00042"
}
}İlk metot ikincisini çağırıyor — varsayılan değer simülasyonu. Bu çok yaygın bir overloading desenidir: basit versiyonu çağır, o da detaylı versiyona yönlendirir.
Pratik Örnek: Mesaj Oluşturucu
public static String mesajOlustur(String alici) {
return mesajOlustur(alici, "Merhaba");
}
public static String mesajOlustur(String alici, String selamlama) {
return mesajOlustur(alici, selamlama, null);
}
public static String mesajOlustur(String alici, String selamlama, String imza) {
StringBuilder sb = new StringBuilder();
sb.append(selamlama).append(", ").append(alici).append("!");
if (imza != null) {
sb.append("\n\n-- ").append(imza);
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(mesajOlustur("Ali"));
// Merhaba, Ali!
System.out.println(mesajOlustur("Ali", "Selam"));
// Selam, Ali!
System.out.println(mesajOlustur("Ali", "Selam", "Mehmet"));
// Selam, Ali!
//
// -- Mehmet
}Bu "telescoping constructor" desenidir — her basit versiyon bir sonrakini çağırır. İşe yarar ama çok fazla parametre olunca Builder pattern daha uygun olur (ileri seviye).
Overloading Tasarım Desenleri
Desen 1: Varsayılan Parametre Simülasyonu
Java'da default parameter yoktur (Python'daki gibi). Overloading ile bunu simüle edebilirsin:
public static String formatTarih(int gun, int ay, int yil) {
return formatTarih(gun, ay, yil, "/");
}
public static String formatTarih(int gun, int ay, int yil, String ayirici) {
return String.format("%02d%s%02d%s%04d", gun, ayirici, ay, ayirici, yil);
}
// Kullanım
formatTarih(15, 3, 2024); // "15/03/2024"
formatTarih(15, 3, 2024, "-"); // "15-03-2024"
formatTarih(15, 3, 2024, "."); // "15.03.2024"Desen 2: Tip Dönüşüm Kolaylığı
public static boolean arasindaMi(int deger, int alt, int ust) {
return deger >= alt && deger <= ust;
}
public static boolean arasindaMi(double deger, double alt, double ust) {
return deger >= alt && deger <= ust;
}
public static boolean arasindaMi(char karakter, char alt, char ust) {
return karakter >= alt && karakter <= ust;
}
// Kullanım
arasindaMi(5, 1, 10); // true
arasindaMi(3.14, 3.0, 4.0); // true
arasindaMi('M', 'A', 'Z'); // trueAynı mantık farklı tiplere uygulanıyor. Kullanıcı tip dönüşümü düşünmek zorunda kalmıyor.
Desen 3: Convenience Methods (Kolaylık Metotları)
// Tam versiyon
public static void log(String seviye, String mesaj, boolean zaman, String dosya) {
StringBuilder sb = new StringBuilder();
if (zaman) {
sb.append("[").append(java.time.LocalDateTime.now()).append("] ");
}
sb.append("[").append(seviye).append("] ").append(mesaj);
System.out.println(sb);
}
// Kolaylık metotları
public static void logInfo(String mesaj) {
log("INFO", mesaj, true, null);
}
public static void logError(String mesaj) {
log("ERROR", mesaj, true, null);
}
public static void logDebug(String mesaj) {
log("DEBUG", mesaj, false, null);
}Bu desende tüm iş tek bir ana metotta yapılır, kolaylık metotları onu uygun parametrelerle çağırır.
Gerçek Dünya: Java Standart Kütüphanede Overloading
Java'nın kendi kütüphanesi overloading'i yoğun kullanır:
String.valueOf()
String.valueOf(42); // "42" — valueOf(int)
String.valueOf(3.14); // "3.14" — valueOf(double)
String.valueOf(true); // "true" — valueOf(boolean)
String.valueOf('A'); // "A" — valueOf(char)
String.valueOf(new int[]{1,2}); // "[I@..." — valueOf(Object)Math sınıfı
Math.abs(-5); // 5 — abs(int)
Math.abs(-5L); // 5L — abs(long)
Math.abs(-5.0f); // 5.0f — abs(float)
Math.abs(-5.0); // 5.0 — abs(double)
Math.max(3, 5); // 5 — max(int, int)
Math.max(3.0, 5.0); // 5.0 — max(double, double)Arrays sınıfı
Arrays.sort(intDizi); // sort(int[])
Arrays.sort(doubleDizi); // sort(double[])
Arrays.sort(stringDizi); // sort(Object[])
Arrays.sort(dizi, 0, 5); // sort(int[], int, int) — aralık belirtmeliOverloading ile İlgili İleri Seviye Notlar
Generic Metotlar (Kısa Bakış)
Java Generics ile tek bir metot birden fazla tipi karşılayabilir. Bu bazen overloading'e alternatiftir:
// Overloading ile
public static int enBuyuk(int a, int b) { return a > b ? a : b; }
public static double enBuyuk(double a, double b) { return a > b ? a : b; }
public static String enBuyuk(String a, String b) { return a.compareTo(b) > 0 ? a : b; }
// Generic ile (tek metot)
public static <T extends Comparable<T>> T enBuyuk(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}Generics'i ilerideki derslerde öğreneceksin. Şimdilik bilmen gereken: bazen tek generic metot, birden fazla overload'dan daha iyi bir çözüm olabilir.
Overloading ve null
void metot(String s) { System.out.println("String"); }
void metot(Integer i) { System.out.println("Integer"); }
metot(null); // DERLEME HATASI — ambiguous!null hem String hem Integer olabilir. Java karar veremez. Cast ile çözersin:
metot((String) null); // "String"
metot((Integer) null); // "Integer"Yaygın Hatalar
1. Sadece Dönüş Tipi Farklı
// DERLEME HATASI
int hesapla(int x) { return x * 2; }
double hesapla(int x) { return x * 2.0; }Dönüş tipi imzanın parçası değil. İmza aynı olduğu için overloading olmaz.
2. Autoboxing Karmaşası
void metot(Integer x) { System.out.println("Integer"); }
void metot(long x) { System.out.println("long"); }
metot(5); // "long" — genişleme, autoboxing'ten öncelikli!int → long genişleme, int → Integer autoboxing'ten önce gelir. Bu beklenmedik olabilir.
3. Varargs Ambiguity
void metot(int... a) { }
void metot(int a, int... b) { }
metot(1, 2); // DERLEME HATASI — ambiguous!Her iki metot da metot(1, 2) çağrısını karşılayabilir. Java karar veremez.
Özet
Method overloading: Aynı isimli, farklı parametreli metotlar tanımlama — Java derleme zamanında doğru metodu seçer.
Farklılık parametrelerde olmalı: tip, sayı veya sıralama. Sadece dönüş tipi veya parametre isimleri yeterli değil.
Overload resolution önceliği: tam eşleşme → genişleme → autoboxing → varargs.
Varargs (
int... args) değişken sayıda argüman kabul eder. Son parametre olmalı, metot başına bir tane.Varsayılan değer simülasyonu için basit overload'un detaylı versiyonu çağırmasını sağla.
Aşırı overloading'den kaçın — belirsiz durumlar (ambiguity) zor debug edilir. Şüphede farklı isim ver.
Varsayılan parametre simülasyonu: Basit overload'un detaylı versiyonu çağırması en yaygın ve en temiz desen.
Java kütüphaneleri overloading'i yoğun kullanır:
println,String.valueOf,Math.abs,Arrays.sorthep overloaded.
Ne Zaman Overloading Yapma
Overloading güçlü ama her zaman doğru çözüm değil:
Metotlar farklı işler yapıyorsa — Farklı isim ver.
hesaplaVergi()vehesaplaKar()iki farklı iş, ikisine dehesapla()deme.Parametre anlamı belirsizleşiyorsa —
olustur(String, String)iki string alıyor ama hangisi isim, hangisi soyisim? Belirsiz overloading'den kaçın.5+ overload varsa — Bu kadar çok overload varsa, muhtemelen Builder pattern veya bir konfigürasyon nesnesi daha uygun.
Alıştırma Fikirleri
maks(int, int),maks(int, int, int),maks(int[])overload'ları yazformatSayi(int)→"42",formatSayi(int, int)→"0042"(padding),formatSayi(double, int)→"3.14"(decimal places)birlesir(String, String),birlesir(String, String, String),birlesir(String...)ile string birleştirme metotları yaz
AI Asistan
Sorularını yanıtlamaya hazır