- Katılım
- 7 Nis 2025
- Konular
- 367
- Mesajlar
- 780
- Çözümler
- 1
- Tepkime puanı
- 121
- Puan
- 93
- Konum
- İstanbul
- Web sitesi
- forumagel.com
Hazır Kod Bankası - Konu 18: Java'da OOP - İleri Kavramlar
Hazır Kod Bankası Serimizin On Sekizinci Konusu: Java'da OOP'nin İleri Kavramları![/B]
Merhaba arkadaşlar! Java'da Nesne Tabanlı Programlamanın (OOP) temellerini gördük (Sınıf, Nesne, Özellik, Metot, Kurucu Metot). Artık Java'nın tamamen nesne tabanlı yapısının ne anlama geldiğini daha iyi anlıyoruz. OOP'yi güçlü, esnek ve bakımı kolay yazılımlar geliştirmek için kullanılan bir yaklaşım haline getiren dört ana prensip vardır: Miras Alma, Çok Biçimlilik, Kapsülleme ve Soyutlama.
Bu konuda, OOP'nin bu dört temel prensibini Java'nın sözdizimi ve kuralları içinde detaylı örneklerle inceleyeceğiz. Miras Alma ve Çok Biçimlilik kavramlarına Python üzerinden genel bir bakış atmıştık (Konu 12), şimdi bunları Java'daki somut uygulamalarıyla pekiştireceğiz ve Kapsülleme ile Soyutlama'ya giriş yapacağız.
1. Miras Alma (Inheritance) Java'da
Miras alma, bir sınıfın (alt sınıf veya türetilmiş sınıf), başka bir sınıftan (ana sınıf veya temel sınıf) özelliklerini ve metotlarını devralmasıdır. Bu, "bir ... türüdür" ("Is-a") ilişkisini kurar ve kod tekrarını önleyerek yeniden kullanılabilirliği artırır.
Java'da Sözdizimi: `extends` anahtar kelimesi kullanılır. Java'da tekli miras vardır, yani bir sınıf sadece tek bir sınıftan miras alabilir.
Java:
// Ana Sınıf (Base Class / Parent Class) - Hayvan.java
public class Hayvan {
String isim;
public Hayvan(String isim) {
this.isim = isim;
}
public void sesCikar() { // Metot tanımlama
System.out.println("Bir hayvan sesi");
}
public void yemekYe() {
System.out.println(this.isim + " yemek yiyor.");
}
}
// Alt Sınıf (Derived Class / Child Class) - Hayvan sınıfından miras alıyor
// Kopek.java
public class Kopek extends Hayvan { // extends ile miras alıyoruz
String irk;
public Kopek(String isim, String irk) {
super(isim); // super() ile ana sınıfın kurucu metodunu çağırıyoruz
this.irk = irk;
}
// Metot Ezme (Method Overriding): Ana sınıftaki metodu alt sınıfta yeniden tanımlama
@Override // Bu annotation (işaretleme) metodun override edildiğini belirtir (iyi pratik)
public void sesCikar() {
System.out.println("Hav hav!"); // Ana sınıfın davranışını değiştiriyoruz
}
// Köpeğe özgü yeni metot
public void getir() {
System.out.println(this.isim + " bir şey getiriyor.");
}
}
// Başka bir Alt Sınıf - Hayvan sınıfından miras alıyor
// Kedi.java
public class Kedi extends Hayvan {
public Kedi(String isim) {
super(isim); // Ana sınıfın kurucu metodunu çağır
}
@Override // sesCikar metodunu eziyoruz
public void sesCikar() {
System.out.println("Miyav!");
}
// Kediye özgü yeni metot
public void tirman() {
System.out.println(this.isim + " tırmanıyor.");
}
}
// Main sınıfı (Test için ayrı bir yerde)
// TestHayvanlar.java
public class TestHayvanlar {
public static void main(String[] args) {
Hayvan hayvan = new Hayvan("Genel");
Kopek kopek = new Kopek("Kont", "Golden");
Kedi kedi = new Kedi("Tekir");
hayvan.yemekYe(); // Miras alınmış metot
kopek.yemekYe(); // Miras alınmış metot
kedi.yemekYe(); // Miras alınmış metot
hayvan.sesCikar(); // Ana sınıf metodu
kopek.sesCikar(); // Ezilmiş (override edilmiş) metot
kedi.sesCikar(); // Ezilmiş (override edilmiş) metot
kopek.getir(); // Alt sınıfa özgü metot
// kedi.getir(); // Hata verir, Kedi sınıfında yok!
}
}
2. Çok Biçimlilik (Polymorphism) Java'da
Çok biçimlilik, farklı nesnelerin aynı metoda çağrı yapıldığında kendi tiplerine özgü farklı davranışlar sergilemesidir. Java'da bu, genellikle Miras Alma ile birlikte görülür. Bir ana sınıf referansı (değişkeni), o ana sınıftan türetilmiş herhangi bir alt sınıfın nesnesini tutabilir. Metot çağrıldığında ise Java, nesnenin gerçek (alt sınıf) tipine bakar ve o tipe ait metodu (eğer ezilmişse) çalıştırır.
Java:
// Önceki örnekteki Hayvan, Kopek, Kedi sınıflarının tanımlı olduğunu varsayalım
// Main sınıfı (Test için)
// TestPolymorphism.java
public class TestPolymorphism {
public static void main(String[] args) {
// Ana sınıf tipinde referanslar, alt sınıf nesnelerini tutuyor
Hayvan hayvan1 = new Kopek("Lessi", "Collie"); // Hayvan referansı -> Kopek nesnesi
Hayvan hayvan2 = new Kedi("Pamuk"); // Hayvan referansı -> Kedi nesnesi
Hayvan hayvan3 = new Hayvan("Generic"); // Hayvan referansı -> Hayvan nesnesi
// Hayvan nesneleri listesi oluşturma (farklı tipler bir arada)
Hayvan[] hayvanDizisi = new Hayvan[3];
hayvanDizisi[0] = hayvan1; // Kopek nesnesi
hayvanDizisi[1] = hayvan2; // Kedi nesnesi
hayvanDizisi[2] = hayvan3; // Hayvan nesnesi
System.out.println("Hayvanlar sırayla ses çıkarıyor:");
// Dizideki her nesne üzerinde döngü
for (Hayvan h : hayvanDizisi) { // Referans tipi Hayvan olmasına rağmen...
h.sesCikar(); // Java nesnenin gerçek tipine bakar ve doğru metodu çağırır
}
// Çıktı:
// Hav hav! (Kopek nesnesinin sesCikar metodu)
// Miyav! (Kedi nesnesinin sesCikar metodu)
// Bir hayvan sesi (Hayvan nesnesinin sesCikar metodu)
}
}
3. Kapsülleme (Encapsulation) Java'da
Kapsülleme, bir nesnenin verilerini (özelliklerini) ve bu veriler üzerinde işlem yapan metotları tek bir birim (sınıf) içinde toplama ve veriye doğrudan erişimi engelleyerek kontrollü erişim sağlama prensibidir. Amaç, nesnenin iç durumunu dış dünyadan gizlemek ve veri tutarlılığını korumaktır.
Java'da Uygulama: Özellikleri `private` erişim belirteci ile tanımlanır (sadece sınıf içinden erişilebilir yapar). Bu özelliklere dışarıdan erişim için `public` Getter (`get...()`) ve Setter (`set...(...)`) metotları kullanılır.
Java:
// KapsullemeOrnegi.java
public class KapsullemeOrnegi {
// Özellikleri private yaparak doğrudan erişimi engelliyoruz (Data Hiding)
private String ad;
private int yas;
// Kurucu metot (Opsiyonel)
public KapsullemeOrnegi(String ad, int yas) {
this.ad = ad;
// Setter kullanarak yaş atama, böylece setter'daki doğrulama çalışır
setYas(yas);
}
// Getter metodu: 'ad' özelliğinin değerini dışarıya verir
public String getAd() {
return ad;
}
// Setter metodu: 'ad' özelliğine dışarıdan değer atama imkanı verir (Bu örnekte doğrudan atıyor)
public void setAd(String ad) {
this.ad = ad;
}
// Getter metodu: 'yas' özelliğinin değerini dışarıya verir
public int getYas() {
return yas;
}
// Setter metodu: 'yas' özelliğine dışarıdan değer atama imkanı verir
// Değer atarken doğrulama yapabiliriz (veri tutarlılığını sağlama)
public void setYas(int yas) {
if (yas > 0 && yas < 120) { // Basit doğrulama
this.yas = yas;
} else {
System.out.println("Hata: Geçersiz yaş değeri!");
}
}
// Main metot (Test için)
public static void main(String[] args) {
KapsullemeOrnegi kisi = new KapsullemeOrnegi("Ali", 30);
// Özelliklere doğrudan ERİŞİLEMEZ (private oldukları için compile time hatası verir)
// System.out.println(kisi.ad); // Hata!
// kisi.yas = 5; // Hata!
// Getter ve Setter metotları ile erişim ve değişiklik yapma
System.out.println("Ad: " + kisi.getAd()); // Getter ile değeri al
kisi.setYas(35); // Setter ile değeri değiştir
System.out.println("Yaş: " + kisi.getYas()); // Getter ile yeni değeri al
kisi.setYas(-5); // Geçersiz değer denemesi - Setter içindeki doğrulama çalışır
System.out.println("Yaş (Geçersiz deneme sonrası): " + kisi.getYas()); // Yaş değişmemiş olmalı
}
}
4. Soyutlama (Abstraction) Java'da
Soyutlama, karmaşık uygulama detaylarını gizleyerek sadece kullanıcının (veya başka geliştiricinin) ihtiyaç duyduğu temel özellikleri gösterme prensibidir. Odak noktası "Ne" yapıldığıdır, "Nasıl" yapıldığı detayları gizlenir.
Java'da Uygulama: Soyutlama genellikle Soyut Sınıflar (Abstract Classes) ve Arayüzler (Interfaces) kullanılarak sağlanır.
- Soyut Sınıflar (`abstract class`):
- `abstract` anahtar kelimesi ile tanımlanır.
- Doğrudan nesnesi oluşturulamaz. (örneğin `new Sekil()` yapamazsınız).
- Hem soyut metotlar (gövdesi olmayan, sadece imzası olan metotlar - alt sınıflar tarafından doldurulması zorunlu) hem de somut metotlar (gövdesi olan, normal metotlar) içerebilir.
- Özellikler (değişkenler) içerebilir.
- Soyut olmayan bir sınıf, soyut bir sınıftan miras alıyorsa (`extends`), ana sınıftaki tüm soyut metotları uygulamak (implement etmek) zorundadır.
Java:// Soyut Sınıf Tanımı abstract class Sekil { // abstract anahtar kelimesi ile soyut sınıf String renk; public Sekil(String renk) { this.renk = renk; } // Soyut Metot - Gövdesi yok, alt sınıflar implement etmeli abstract double alanHesapla(); // Somut Metot - Gövdesi var public void bilgiyiYazdir() { System.out.println("Bu bir " + renk + " şekildir."); } } // Soyut sınıftan miras alan somut sınıf class Daire extends Sekil { double yaricap; public Daire(String renk, double yaricap) { super(renk); // Ana sınıfın kurucusunu çağır this.yaricap = yaricap; } @Override // Soyut metodu implement etme zorunluluğu! double alanHesapla() { // abstract anahtar kelimesi kullanılmaz, govdesi yazilir return Math.PI * yaricap * yaricap; } } // Main (Test için) // TestSoyutSekil.java public class TestSoyutSekil { public static void main(String[] args) { // Sekil s = new Sekil("Kırmızı"); // Hata verir, soyut sınıftan nesne oluşturulamaz! Daire d = new Daire("Mavi", 5.0); d.bilgiyiYazdir(); // Miras alınan somut metot System.out.println("Alan: " + d.alanHesapla()); // Implement edilen soyut metot } }
- Arayüzler (`interface`):
- `interface` anahtar kelimesi ile tanımlanır.
- Soyutlamanın en saf halidir. Java'da çoklu mirasın bir yolu olarak kullanılır (bir sınıf birden çok arayüzü uygulayabilir).
- Java 8 öncesinde sadece soyut metotlar (public ve abstract varsayılan) ve sabitler (public static final varsayılan) içerebilirdi.
- Java 8 sonrası `default` ve `static` metotlar da içerebilir.
- Bir sınıf bir arayüzü uyguluyorsa (`implements`), arayüzdeki (default ve static olmayan) tüm metotları uygulamak zorundadır.
- Bir sınıf birden çok arayüzü uygulayabilir (`class MyClass implements Interface1, Interface2 { ... }`).
- Arayüzlerin doğrudan nesnesi oluşturulamaz.
Java:// Arayüz Tanımı interface Cizebilir { // Metotlar varsayılan olarak public ve abstract'tır (Java 8 öncesi) void ciz(); // Soyut metot - govdesi yok // Java 8+ ile default metotlar default void bilgiVer() { System.out.println("Bu nesne çizilebilir."); } } // Arayüzü uygulayan sınıf class Kare implements Cizebilir { // implements ile arayuzu uyguluyoruz double kenar; public Kare(double kenar) { this.kenar = kenar; } @Override // Arayüzdeki metodu implement etme zorunluluğu! public void ciz() { // abstract anahtar kelimesi kullanılmaz, govdesi yazilir System.out.println("Kare çiziliyor (Kenar: " + kenar + ")"); } } // Başka bir arayüzü uygulayan sınıf class Cember implements Cizebilir { double yaricap; public Cember(double yaricap) { this.yaricap = yaricap; } @Override public void ciz() { System.out.println("Çember çiziliyor (Yarıçap: " + yaricap + ")"); } } // Main (Test için) // TestArayuz.java public class TestArayuz { public static void main(String[] args) { // Cizebilir c = new Cizebilir(); // Hata verir, arayüzden nesne oluşturulamaz! // Arayüz tipinde referans, uygulayan sınıfların nesnelerini tutabilir (Çok Biçimlilik!) Cizebilir sekil1 = new Kare(10.0); Cizebilir sekil2 = new Cember(5.0); sekil1.ciz(); // Kare'nin ciz() metodu çalışır sekil2.ciz(); // Cember'in ciz() metodu çalışır sekil1.bilgiVer(); // Arayüzdeki default metot sekil2.bilgiVer(); // Arayüzdeki default metot } }
Sıra Sizde!
Java'da OOP'nin dört ana prensibi (Miras Alma, Çok Biçimlilik, Kapsülleme, Soyutlama) program tasarımında çok önemlidir. Bu kavramları pekiştirmek için:
- Miras Alma örneğini (Hayvan -> Kopek/Kedi) kendiniz Java'da kodlayıp çalıştırın. `super()` kullanımını farklı senaryolarda deneyin.
- Çok Biçimlilik örneğini Java'da kodlayıp farklı alt sınıflardan nesneleri bir ana sınıf dizisinde/listesinde toplayarak metotları çağırmayı deneyin.
- Kapsülleme örneğini (özellikleri `private` yapıp Getter/Setter ekleme) kendi bir sınıfınız üzerinde uygulayın. Setter metotlarına basit doğrulama kuralları eklemeyi deneyin.
- Basit bir `abstract class` tanımlayın (örneğin `Calisan` soyut sınıfı, içinde `abstract double maasHesapla()` metodu olsun). Bu sınıftan miras alan somut sınıflar (örneğin `TamZamanliCalisan`, `YariZamanliCalisan`) tanımlayıp soyut metodu kendi mantıklarına göre implement edin.
- Basit bir `interface` tanımlayın (örneğin `HareketEdebilir` arayüzü, içinde `void yuru()`, `void kos()` metotları olsun). Bu arayüzü uygulayan farklı sınıflar (`Insan`, `Robot`) tanımlayın ve metotları implement edin. Arayüz referansı üzerinden çok biçimliliği deneyin.
Serinin Geleceği?[/B]
Java'da OOP'nin dört temel prensibini tamamladık. Bu, Java programlamada sağlam bir temel oluşturur.
Seriyi buradan sonra nasıl devam ettirelim?
- Java'da temel kütüphane sınıfları ve veri yapıları (Diziler - Arrays, ArrayList, HashMap, String metotları, Scanner ile girdi alma, Dosya I/O)?
- Java Hata Yönetimi (Exception Handling) derinlemesine ve kendi hata türlerini tanımlama?
- Temel Veri Yapıları ve Algoritmalar (Bağlı Listeler, Ağaçlar, Grafikler vb.)?
- Başka bir programlama diline giriş (C#, C++ gibi)?
- Web geliştirme Frameworklerine giriş (Java Spring/Spring Boot, Python Flask/Django, JS React/Vue/Angular, PHP Laravel/Symfony)?
- Mobil geliştirme temelleri (Android Studio ile)?
- Belirli bir proje türüne odaklanma (Örn: Basit Java Konsol Uygulaması Yapımı, Basit Web API Yapımı)?
- Veya başka önerileriniz mi var?
Umarım bu konu OOP bilginizi Java özelinde daha da pekiştirmiştir. Görüşmek üzere!
Bu konu, "Hazır Kod Bankası" serisinin on sekizinci parçasıdır ve "Yazılım Bilgi ve Yeni Başlayanlar İçin" kategorisi altında paylaşılmıştır.