Dahili, Yuvalanmış ve Anonim Sınıflar
Coddy'nin Java Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 49 / 87.
Java, sınıfları diğer sınıfların içinde tanımlamanıza olanak tanır. Bu dahili sınıflar (inner classes), ilgili işlevleri bir araya getirerek kodu düzenlemeye yardımcı olur ve dış sınıfın üyelerine doğrudan erişebilir.
Bir iç içe geçmiş dahili sınıf (nested inner class), başka bir sınıfın üyesi olarak tanımlanır. Özel (private) olanlar da dahil olmak üzere, dış sınıfın tüm alanlarına ve metotlarına erişimi vardır:
class Outer {
private String message = "Hello";
class Inner {
void display() {
System.out.println(message); // Özel (private) alana erişebilir
}
}
}
// Kullanım
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display(); // Çıktı: HelloBir yerel iç sınıf (local inner class), bir metodun içinde tanımlanır. Yalnızca o metodun içinde kullanılabilir ve etkili bir şekilde final (effectively final) olan yerel değişkenlere erişebilir:
void process() {
String prefix = "Result: ";
class LocalHelper {
void print(int value) {
System.out.println(prefix + value);
}
}
new LocalHelper().print(42);
}Bir anonim iç sınıf (anonymous inner class), tek bir ifadede oluşturulan ve örneklendirilen, ismi olmayan bir sınıftır. Genellikle arayüzleri uygulamak veya sınıfları anında genişletmek için kullanılır:
Comparator<String> comp = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
};Dahili sınıflar, bir sınıfın yalnızca başka bir sınıfla ilgili olduğu durumlarda özellikle yararlıdır; bu da kodunuzun düzenli ve kapsüllenmiş kalmasını sağlar.
Görev
KolayÜç tür dahili sınıfın (inner class) tümünü sergileyen bir alışveriş sepeti sistemi oluşturalım. Öğeleri temsil etmek için bir yuvalanmış dahili sınıf (nested inner class), indirimleri hesaplamak için bir yerel dahili sınıf (local inner class) ve nihai makbuzu biçimlendirmek için bir anonim dahili sınıf (anonymous inner class) kullanan bir ShoppingCart oluşturacaksınız.
Kodunuzu iki dosya halinde düzenleyeceksiniz:
ShoppingCart.java: Bir alışveriş deneyimini yöneten dış sınıfı oluşturun. ShoppingCart sınıfınızın özel bircustomerName(String) alanı olmalıdır.ShoppingCart içinde, iki özel alana sahip
Itemadında bir yuvalanmış dahili sınıf tanımlayın:name(String) veprice(double). Item sınıfına her iki alanı da başlatan bir yapıcı (constructor) ve şu değeri döndüren birgetDetails()yöntemi verin:[name]: $[price]ShoppingCart sınıfınızın müşteri adını alan bir yapıcıya ve bir Item ile bir indirim yüzdesi (double) kabul eden
checkout()adlı bir yönteme ihtiyacı vardır.checkout()içinde:- İndirim yüzdesini uyguladıktan sonra fiyatı döndüren
applyDiscount(double originalPrice)yöntemine sahipDiscountCalculatoradında bir yerel dahili sınıf oluşturun. - Nihai fiyatı hesaplamak için yerel sınıfı kullanın.
- Makbuzu biçimlendirmek için
Formatterarayüzünü (bunu siz tanımlayacaksınız) uygulayan bir anonim dahili sınıf oluşturun. Anonim sınıf, çok satırlı bir makbuz dizesi döndüren birformat()yöntemini geçersiz kılmalıdır (override).
checkout()yöntemi, tam olarak şu biçimde biçimlendirilmiş makbuz dizesini döndürmelidir:--- Receipt --- Customer: [customerName] Item: [item details from getDetails()] Discount: [discount]% Final Price: $[calculated price]- İndirim yüzdesini uyguladıktan sonra fiyatı döndüren
Formatter.java: Tek bir yöntemi olan basit bir arayüz tanımlayın:String format(). Bu arayüz, checkout yöntemi içindeki anonim dahili sınıfınız tarafından uygulanacaktır.Main.java: Alışveriş sepetinizi hayata geçirin! Üç girdi alacaksınız: müşteri adı (String), ürün adı (String) ve ürün fiyatı (double). İndirim yüzdesi10.0olarak sabitlenmiştir.Müşteri adıyla bir ShoppingCart oluşturun. Ardından dış sınıf referans sözdizimini kullanarak bir Item oluşturun:
cart.new Item(name, price). Ürün ve indirimlecheckout()yöntemini çağırın ve döndürülen makbuzu yazdırın.
Sırasıyla üç girdi alacaksınız: müşteri adı, ürün adı ve ürün fiyatı.
Örneğin, girdiler Alice, Laptop ve 1000.0 ise, %10 indirimden sonraki nihai fiyat 900.0 olacaktır.
Her bir dahili sınıf türünün nasıl farklı bir amaca hizmet ettiğine dikkat edin: yuvalanmış sınıf ilgili verileri dış sınıfla gruplandırır, yerel sınıf yalnızca bir yöntem içinde gereken mantığı kapsüller ve anonim sınıf bir arayüzün hızlı, tek seferlik bir uygulamasını sağlar!
Kopya kağıdı
Java, sınıfları diğer sınıfların içinde tanımlamanıza olanak tanır. Bu dahili sınıflar (inner classes), ilgili işlevleri bir araya getirerek kodu düzenlemeye yardımcı olur ve dış sınıfın üyelerine doğrudan erişebilir.
Yuvalanmış Dahili Sınıf (Nested Inner Class)
Bir yuvalanmış dahili sınıf, başka bir sınıfın üyesi olarak tanımlanır. Özel (private) olanlar da dahil olmak üzere dış sınıfın tüm alanlarına ve metotlarına erişimi vardır:
class Outer {
private String message = "Hello";
class Inner {
void display() {
System.out.println(message); // Can access private field
}
}
}
// Usage
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display(); // Prints: HelloYerel Dahili Sınıf (Local Inner Class)
Bir yerel dahili sınıf, bir metodun içinde tanımlanır. Sadece o metodun içinde kullanılabilir ve efektif olarak final (effectively final) olan yerel değişkenlere erişebilir:
void process() {
String prefix = "Result: ";
class LocalHelper {
void print(int value) {
System.out.println(prefix + value);
}
}
new LocalHelper().print(42);
}Anonim Dahili Sınıf (Anonymous Inner Class)
Bir anonim dahili sınıf, ismi olmayan, tek bir ifade içinde oluşturulan ve örneği alınan bir sınıftır. Genellikle arayüzleri (interfaces) uygulamak veya sınıfları anında genişletmek için kullanılır:
Comparator<String> comp = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
};Dahili sınıflar, bir sınıfın yalnızca başka bir sınıfla ilgili olduğu durumlarda kodunuzu düzenli ve kapsüllenmiş (encapsulated) tutmak için özellikle yararlıdır.
Kendin dene
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Girdileri oku
String customerName = scanner.nextLine();
String itemName = scanner.nextLine();
double itemPrice = scanner.nextDouble();
double discount = 10.0;
// TODO: Müşteri adıyla bir ShoppingCart oluşturun
// TODO: cart.new Item(itemName, itemPrice) kullanarak bir Item oluşturun
// TODO: item ve discount ile checkout() metodunu çağırın, ardından sonucu yazdırın
}
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesnelerthis Anahtar KelimesiMetotlarAlanlar (Öznitelikler)Yapıcı MetotYapıcı Metot Aşırı YüklemeÖzet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtım (extends)super Anahtar KelimesiMetot Geçersiz Kılma (@Override)Yapıcı Metot ZincirlemeObject SınıfıTekli ve Çok Seviyeli KalıtımNeden Çoklu Sınıf Kalıtımı Yok?Özet - Çalışan Hiyerarşisi7Özel Metotlar ve Object Sınıfı
toString() Metoduequals() ve hashCode()clone() MetoducompareTo() ve ComparableComparator ArayüzüÖzet - Özel Sıralama2Erişim Belirleyiciler ve Kapsülleme
Erişim Seviyelerine Genel BakışGetter ve Setter MetotlarıBilgi Gizlemefinal Anahtar KelimesiÖzet - Banka Hesabı Yöneticisi5Polimorfizm
Metot Aşırı Yükleme TemelleriMetot Geçersiz Kılma (Çalışma Zamanı)Upcasting ve Downcastinginstanceof OperatörüSoyut Sınıflar ve MetotlarÖzet - Şekil Hesaplayıcı8İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımAgregasyon vs KompozisyonDahili, Yuvalanmış ve Anonim SınıflarEnum'lar ve Enum MetotlarıRecords (Java 16+)Sealed Classes (Java 17+)11Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıBuilder KalıbıObserver KalıbıStrategy Kalıbı14Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi3Sınıf Özellikleri ve Statik Üyeler
Instance ve Statik DeğişkenlerStatik MetotlarStatik BloklarSabitler (static final)Özet - Sayaç ve Utility6Arayüzler ve Soyut Sınıflar
Arayüzlere GirişArayüzleri UygulamaÇoklu Arayüz UygulamaArayüzlerde Default ve StaticSoyut Sınıflar ve ArayüzlerFonksiyonel ArayüzlerÖzet - Ödeme Sistemi9Generics
Generics'e GirişGeneric SınıflarGeneric MetotlarSınırlandırılmış Tip ParametreleriWildcard'lar (?, extends, super)Özet - Generic Container12Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıYineleyici Kalıbı