Bölüm 4.2: Sarmalama
Giriş
Öğrenme Çıktıları
Veriyi ve onu işleyen metotları tek sınıfta toplamayı, iç ayrıntıları gizlemeyi (bilgi saklama) ve “ne / nasıl” ayrımını örnekle anlatmak.
Bir metodun ön koşulunu ve son koşulunu yorum satırıyla belirtmek ve kodda kontrol etmek.
public, private, protected ve paket erişiminin kimlere açık olduğunu tablo ile söylemek.
Alanları private yapıp doğrulama yapan erişim metotları yazmak; this.alan = alan kalıbını kullanmak.
Sınıfın dış yüzünü değiştirmeden iç yapısını değiştirebilmek; interface ve implements ile tanışmak.
package ve import ile sınıfları gruplamak, derleyip çalıştırmak; sınıf adı çakışmalarını çözmek.
Sarmalama ve Bilgi Saklama
Sarmalama (Encapsulation)
- Sarmalama (encapsulation): bir nesnenin verisini (alanlar) ve bu veriyi işleyen metotları tek birimde, sınıfta toplamak.
- Veri dışarıya kapatılır (
private); dışarıdan yalnızca sınıfın sunduğu metotlar çağrılabilir. - Benzetme: ilaç kapsülü. İçindeki toz görünmez, yalnızca kapsülü yutarsınız. Sınıf da kendi verisinin bekçisidir: geçersiz bir değer (ör. 75. saniye) içeri giremez.
Sarmalama, nesne yönelimli programlamanın dört temel ilkesinden biridir (diğerleri: kalıtım, çok biçimlilik, soyutlama).
Sarmalama ve Bilgi Saklama
Bilgi Saklama
- Bilgi saklama (information hiding), soyutlama (abstraction) olarak da adlandırılır. Tasarım, ne yapıldığını nasıl yapıldığından ayırmalıdır.
- Bir metot, iç ayrıntıları bilinmeden de kullanılabilmelidir: metodun ne işe yaradığını bilmek yeterli olmalıdır.
- Arabada fren, gaz pedalı ve direksiyonu görür, kullanırız; bu parçaların iç mekaniğini bilmeyiz.
Aynı fikir koddadır: System.out.println metodunu sürekli kullanırız ama ekrana yazmanın nasıl gerçekleştiğini bilmemiz gerekmez.
Sarmalama ve Bilgi Saklama
Bilgi Saklama: Kod
public class VeriIslemleri { private VeritabaniBaglantisi baglanti; // metodun iç yapısı bilinmeden de kullanılabilir. public void veriEkle(String veri) { baglanti = new VeritabaniBaglantisi(); baglanti.baglan(); baglanti.veriEkle(veri); baglanti.kapat(); } }
public class Ana { public static void main(String[] args) { VeriIslemleri islem = new VeriIslemleri(); islem.veriEkle("Ayşe"); } }
Bağlantı açıldı Eklendi: Ayşe Bağlantı kapatıldı
Anasınıfı yalnızcaislem.veriEkle("Ayşe")der: ne istediğini söyler.- Bağlantıyı açmak, veriyi yazmak, kapatmak (nasıl)
VeriIslemleriiçinde gizlidir. baglantialanıprivate: dışarıdan görülemez, değiştirilemez.VeritabaniBaglantisiburada ekrana yazan basit bir sınıftır; gerçek bir veri tabanı sürücüsü olsaydı bileAnadeğişmezdi.
Sarmalama ve Bilgi Saklama · Adım adım kod izleme
Tek Çağrının Arkası: Adım Adım
new VeriIslemleri() heap'te bir nesne oluşturur; islem bu nesneyi gösterir (referans). baglanti henüz null.
Ana'nın yaptığı tek şey bu çağrıdır. Yeni bir çerçeve açılır, veri parametresi "Ayşe" olur.
Gizli iş başlar: ikinci nesne oluşur, private baglanti onu gösterir.
baglan() çağrılır: yığında üç çerçeve var. Ana bundan habersiz.
Veri, bağlantı nesnesinin veriEkle metoduna gider: aynı ad, başka sınıf.
Bağlantı kapatılır. Üç adımın hepsi tek çağrının arkasında saklı.
main'e dönülür. Kullanıcı tek satır yazdı, ayrıntıyı bilmedi: bilgi saklama.
public class VeriIslemleri { private VeritabaniBaglantisi baglanti; // metodun iç yapısı bilinmeden de kullanılabilir. public void veriEkle(String veri) { baglanti = new VeritabaniBaglantisi(); baglanti.baglan(); baglanti.veriEkle(veri); baglanti.kapat(); } } public class Ana { public static void main(String[] args) { VeriIslemleri islem = new VeriIslemleri(); islem.veriEkle("Ayşe"); } }
Ön ve Son Koşullar
Ön ve Son Koşullar
Ön koşul (precondition)
Metot çağrılmadan önce doğru olduğu varsayılan koşul. Sağlamak çağıranın sorumluluğudur.
public class VeriIslemleri { // Ön koşul: veri != null public void veriEkle(String veri) { // verinin null olup olmadığını kontrol et // ... } }
Son koşul (postcondition)
Ön koşul sağlandıysa, metot bittikten sonra doğru olacağı garanti edilen durum. Sağlamak metodun sorumluluğudur.
public class VeriIslemleri { // Son koşul: veri tabanına veri eklendiyse true döner public boolean veriEkle(String veri) { // veriyi ekleyip eklemediğini kontrol et // ... return true; } }
true döndüreyim.” Kullanıcı yalnızca sözleşmeyi bilir, gövdeyi bilmez.Ön ve Son Koşullar
Sözleşme: Tam Örnek
public class VeriIslemleri { private int kayitSayisi = 0; /** * Veri tabanına bir kayıt ekler. * Ön koşul: veri null değil ve boş değil. * Son koşul: eklendiyse true döner, * kayitSayisi 1 artar. */ public boolean veriEkle(String veri) { if (veri == null || veri.isEmpty()) { return false; // ön koşul bozuk } // ... veriyi veri tabanına ekle ... kayitSayisi++; return true; // son koşul sağlandı } public int getKayitSayisi() { return kayitSayisi; } }
// main içinde: VeriIslemleri islem = new VeriIslemleri(); System.out.println(islem.veriEkle("Ali")); System.out.println(islem.veriEkle("")); System.out.println(islem.veriEkle(null)); System.out.println(islem.getKayitSayisi());
true false false 1
/** ... */bir Javadoc yorumudur: metodun nasıl kullanılacağını anlatır.- Ön koşul bozulursa metot hiçbir şey eklemez,
falsedöndürür.
Ön ve Son Koşullar · Adım adım kod izleme
Sözleşme: Kod İzleme
Nesne yeni oluştu: kayitSayisi = 0. Sözleşme: veri null ve boş olmamalı.
"Ayşe" null değil ve boş değil: koşul yanlış, if bloğu atlanır.
Son koşul yerine getirilir: sayaç 1 artar ve true döner.
veri == null doğru; || kısa devre yapar. null.isEmpty() hiç çağrılmaz, NullPointerException olmaz.
Ön koşul bozuk: metot nesneye dokunmadan false döndürür.
"" null değil ama boş: sağ taraf doğru, yine false. Sayaç değişmez.
Geçerli veri: sayaç 2 olur, true.
Dört çağrıdan yalnızca sözleşmeye uyan ikisi kayıt ekledi: 2. Nesnenin durumu hiçbir çağrıda bozulmadı.
public boolean veriEkle(String veri) { if (veri == null || veri.isEmpty()) { return false; // ön koşul bozuk } kayitSayisi++; return true; // son koşul sağlandı } // main içinde: VeriIslemleri islem = new VeriIslemleri(); System.out.println(islem.veriEkle("Ayşe")); System.out.println(islem.veriEkle(null)); System.out.println(islem.veriEkle("")); System.out.println(islem.veriEkle("Can")); System.out.println(islem.getKayitSayisi());
Ön ve Son Koşullar
Ön Koşul Bozulunca Ne Yapmalı?
| Yaklaşım | Örnek | Çağıran ne fark eder? |
|---|---|---|
| Sessizce yok saymak | setSaniye(75) hiçbir şey yapmaz | Hiçbir şey; hata gözden kaçabilir |
| Durum döndürmek | veriEkle(null) → false | Dönüş değerine bakarsa fark eder |
| İstisna fırlatmak | throw new IllegalArgumentException(...) | Yakalamazsa program durur; hata kaybolmaz |
public void setSaniye(int saniye) { if (saniye < 0 || saniye > 59) throw new IllegalArgumentException( "saniye 0-59 olmalı: " + saniye); this.saniye = saniye; } // main içinde: DijitalSaat s = new DijitalSaat(); try { s.setSaniye(30); s.setSaniye(75); System.out.println("buraya gelinmez"); } catch (IllegalArgumentException e) { System.out.println("Hata: " + e.getMessage()); } System.out.println(s.getSaniye());
Hata: saniye 0-59 olmalı: 75 30
- İstisna, hatalı değeri çağrının yapıldığı yerde görünür kılar; nesnenin durumu değişmez (30 kalır).
publicmetotlarda argüman hatası için Java'nın alışılmış seçimiIllegalArgumentException'dır.- Seçilen yaklaşım, sözleşmenin parçası olarak belgelenmelidir.
Ön ve Son Koşullar
Sözleşmeyi Javadoc ile Yazmak
/** * Hesaptan para çeker. * @param miktar çekilecek tutar; {@code 0 < miktar <= bakiye} olmalı * @return işlemden sonraki bakiye (eski bakiye - miktar) * @throws IllegalArgumentException miktar bu aralıkta değilse */ public double paraCek(double miktar) { if (miktar <= 0 || miktar > bakiye) throw new IllegalArgumentException("Geçersiz miktar: " + miktar); bakiye -= miktar; return bakiye; }
@param: her parametre ve ön koşulu. @return: dönüş değeri, yani son koşul. @throws: sözleşme bozulunca ne olacağı.
javadoc -d belge BankaHesabi.java komutu bu yorumlardan HTML belgeler üretir. Java kütüphanesinin çevrim içi belgeleri de böyle oluşturulur.
Metodun ne yaptığı ve kullanım koşulları. Nasıl yaptığı yazılmaz: o, gizlenen gerçeklemedir ve değişebilir.
Gövdeyi hiç görmeyecek olan kullanıcı için. Sınıfın arayüzü, imzalar ve bu yorumların toplamıdır.
Ön ve Son Koşullar
assert ile Değişmezi Denetlemek
class Sayac { private int deger; // değişmez: 0 <= deger <= 9 void arttir() { deger = deger + 1; // hata: 9'dan sonra 10 assert deger >= 0 && deger <= 9 : "deger=" + deger; } } // main içinde: Sayac s = new Sayac(); for (int i = 0; i < 10; i++) s.arttir(); System.out.println("bitti");
java Ana
bitti
java -ea Ana
Exception in thread "main" java.lang.AssertionError: deger=10 at Sayac.arttir(Ana.java:5)
assert koşul : mesaj;koşul yanlışsaAssertionErrorfırlatır. Sınıf değişmezini ve son koşulları geliştirme sırasında denetlemek içindir.- Denetimler varsayılan olarak kapalıdır;
-ea(enable assertions) seçeneğiyle açılır. Kapalıyken hata sessizce geçer:bitti. publicmetodun argümanlarıassertile denetlenmez: kapalıyken denetim hiç yapılmaz. Argüman için istisna, iç tutarlılık içinassert.
Erişim Belirleyiciler
Erişim Belirleyiciler
- Erişim belirleyici (access modifier): bir sınıfa, alana veya metoda kimin erişebileceğini belirleyen anahtar sözcük.
public: diğer sınıflar tarafından doğrudan erişilebilir.private: yalnızca sınıfın içinden erişilebilir; dışarıdan erişim derleyici tarafından engellenir.- Sınıflar genellikle
publictanımlanır. - Sınıfın alanları genellikle
privatetanımlanır. - Alanlara erişmek ve onları değiştirmek için
publicmetotlar kullanılır.
public class Ogrenci { // herkese açık sınıf private String ad; // gizli alan private int not; // gizli alan public int getNot() { // açık metot return not; } }
Kural: alanlar gizli, davranışlar açık.
Erişim Belirleyiciler
Dört Erişim Düzeyi
| Belirleyici | Aynı sınıf | Aynı paket | Alt sınıf (başka paket) | Her yer |
|---|---|---|---|---|
public | ✓ | ✓ | ✓ | ✓ |
protected | ✓ | ✓ | ✓ | ✗ |
| (yazılmazsa) paket erişimi | ✓ | ✓ | ✗ | ✗ |
private | ✓ | ✗ | ✗ | ✗ |
- Belirleyici yazılmazsa paket erişimi (package-private, “default”) geçerlidir: yalnızca aynı paketteki sınıflar erişir.
protectedalt sınıflar içindir: başka paketteki alt sınıf da erişir.- Kural olarak en kısıtlayıcı düzey tercih edilir: önce
private, gerçekten gerekirse daha açık bir düzey. - Üst düzey bir sınıf yalnızca
publicya da paket erişimli olabilir.
Erişim Belirleyiciler
private Alana Erişim Denemesi
public class Test { public static void main(String[] args) { DijitalSaat s = new DijitalSaat(); s.saniye = 75; } }
Test.java:4: error: saniye has private access in DijitalSaat
s.saniye = 75;
^
1 errorsaniye,DijitalSaatiçindeprivatetanımlıdır.- Başka bir sınıftan
s.saniyeyazmak derleme hatasıdır: program hiç çalışmaz. - Alan
publicolsaydıs.saniye = 75;sessizce kabul edilir, saat geçersiz bir duruma düşerdi. - Çözüm: değişikliği sınıfın kendi metoduna yaptırmak:
s.setSaniye(75);Metot geçersiz değeri reddeder.
Erişim Belirleyiciler
private Sınıf Düzeyindedir
class Kesir { private int pay, payda; Kesir(int pay, int payda) { this.pay = pay; this.payda = payda; } Kesir carp(Kesir diger) { // diger'in private alanları: izinli return new Kesir(pay * diger.pay, payda * diger.payda); } @Override public String toString() { return pay + "/" + payda; } } // main içinde: Kesir k = new Kesir(2, 3).carp(new Kesir(3, 4)); System.out.println(k);
6/12
- Erişim denetimi nesneye göre değil, sınıfa göre yapılır:
Kesir'in kodu, herKesirnesnesininprivatealanlarını okuyabilir. carp,equals,compareTogibi iki nesneyi birlikte işleyen metotlar bu sayede getter gerektirmez.- Başka bir sınıfta aynı satır derlenmez:
error: pay has private access in Kesir
Getter ve Setter
DijitalSaat Sınıfı
public class DijitalSaat { private int saat = 0; private int dakika = 0; private int saniye = 0; public int getSaniye() { return this.saniye; } public void setSaniye(int saniye) { if (saniye >= 0 && saniye < 60) { this.saniye = saniye; } } }
- Getter (erişimci): alanın değerini döndürür.
- Setter (değiştirici): yeni değeri önce kontrol eder, geçerliyse atar.
- UML'de
-private,+public demektir.
Getter ve Setter · Adım adım kod izleme
Setter Koruması: Adım Adım
Nesne oluşturulur, saniye alanı 0 ile başlar. s nesneyi gösterir.
setSaniye(45): parametre saniye = 45. this, metodu çağıran nesnedir. Koşul doğru.
this.saniye = saniye; soldaki nesnenin alanı, sağdaki parametredir. Alan 45 olur.
setSaniye(75): koşul yanlış, atama satırı atlanır. Geçersiz değer nesneye giremez.
getSaniye() alanın değerini döndürür: 45. Alan hâlâ geçerli.
Ekrana 45 yazılır. Nesnenin durumu baştan sona geçerli kaldı: sarmalamanın amacı budur.
public class DijitalSaat { private int saniye = 0; public int getSaniye() { return this.saniye; } public void setSaniye(int saniye) { if (saniye >= 0 && saniye < 60) { this.saniye = saniye; } } } // SaatTest.main içinde: DijitalSaat s = new DijitalSaat(); s.setSaniye(45); s.setSaniye(75); System.out.println(s.getSaniye());
Getter ve Setter
this ve Gölgeleme
Doğru
public void setSaniye(int saniye) { if (saniye >= 0 && saniye < 60) { this.saniye = saniye; } }
Hatalı (ama derlenir!)
public class Kutu { private int en; public int getEn() { return en; } public void setEn(int en) { en = en; } }
- Parametrenin adı alanla aynıysa, metot içinde
saniyeadı parametreyi gösterir: parametre alanı gölgeler (shadowing). this, metodu çağıran nesnenin kendisidir.this.saniyeher zaman alandır.- Hatalı sürümde
en = en;parametreyi kendisine atar; alan değişmez.k.setEn(5)sonrasık.getEn():
0
Derleyici hata vermez; hata ancak çalıştırınca fark edilir. Bu yüzden setter'larda this. alışkanlığı önemlidir.
Getter ve Setter
Erişim Metotları
public class DijitalSaat { private int saat = 0; // 0..23 private int dakika = 0; // 0..59 private int saniye = 0; // 0..59 public int getSaat() { return saat; } public int getDakika() { return dakika; } public int getSaniye() { return saniye; } public void setSaat(int saat) { if (saat >= 0 && saat < 24) this.saat = saat; } public void setDakika(int dakika) { if (dakika >= 0 && dakika < 60) this.dakika = dakika; } public void setSaniye(int saniye) { if (saniye >= 0 && saniye < 60) this.saniye = saniye; } public void goster() { System.out.printf("%02d:%02d:%02d%n", saat, dakika, saniye); } }
DijitalSaat s = new DijitalSaat(); s.setSaat(9); s.setDakika(5); s.setSaniye(30); s.goster(); s.setSaat(24); // reddedilir s.setDakika(-3); // reddedilir s.goster();
09:05:30 09:05:30
- Adlandırma:
dakika→getDakika(),setDakika(int). booleanalanda erişimciisile başlar:isAktif().
Getter ve Setter
Neden public Alan Değil?
public alan
public class Saat { public int saniye; } // başka bir sınıfta: s.saniye = -5; // kabul edilir!
- Her yerden, her değer yazılabilir.
- Kural (0–59) her kullanıcıya bırakılır; biri unutursa nesne bozulur.
- Alanın adı/tipi değişirse onu kullanan tüm sınıflar değişir.
private alan + metot
public class Saat { private int saniye; public void setSaniye(int s) { if (s >= 0 && s < 60) saniye = s; } }
- Kural tek bir yerde, sınıfın içinde kontrol edilir.
- Salt okunur alan mümkün: yalnızca getter yazılır.
- İç yapı değişse de metotların imzası aynı kalabilir.
Java 16+: yalnızca veri taşıyan değiştirilemez sınıflar için record Nokta(int x, int y) { } yazılabilir; alanlar otomatik private final olur, erişimciler x() ve y() adını alır.
Getter ve Setter
Setter Koruması: Etkileşimli Deneme
“setter ile ata” s.setSaniye(75) gibi çağırır: geçersiz değer reddedilir. “alan public olsaydı” s.saniye = 75 gibi doğrudan yazar: nesne geçersiz duruma düşer (kırmızı). Geçerli aralıklar: saat 0–23, dakika ve saniye 0–59.
Örnek: Banka Hesabı
BankaHesabi: Alanlar
public class BankaHesabi { private int hesapNumarasi; // Hesap numarası private double bakiye; // Hesap bakiyesi private String hesapTuru; // "Vadesiz" / "Vadeli" public BankaHesabi(int hesapNumarasi, double bakiye, String hesapTuru) { this.hesapNumarasi = hesapNumarasi; this.bakiye = bakiye; this.hesapTuru = hesapTuru; } public int getHesapNumarasi() { return hesapNumarasi; } public double getBakiye() { return bakiye; } public String getHesapTuru() { return hesapTuru; } // ... para yatırma ve çekme metotları
- Üç alan da
private: hesap numarasını veya bakiyeyi kimse doğrudan değiştiremez. - Yapıcı (constructor) nesneyi ilk değerleriyle kurar;
this.bakiye = bakiyekalıbı. - Yalnızca getter var, setter yok:
setBakiyeolmadığı için bakiye yalnızca işlemlerle değişir.
Örnek: Banka Hesabı
BankaHesabi: Yatırma ve Çekme
// ... // Para yatırma işlemi public void paraYatir(double miktar) { if (miktar > 0) { bakiye += miktar; System.out.println(miktar + " TL yatırıldı. Yeni bakiye: " + bakiye); } else { System.out.println("Yatırılan miktar geçersiz."); } } // Para çekme işlemi public void paraCek(double miktar) { if (miktar <= bakiye && miktar > 0) { bakiye -= miktar; System.out.println(miktar + " TL çekildi. Kalan bakiye: " + bakiye); } else if (miktar > bakiye) { System.out.println("Yetersiz bakiye."); } else { System.out.println("Çekilen miktar geçersiz."); } }
- Her işlem önce ön koşulu kontrol eder:
miktar > 0, çekmede ayrıcamiktar ≤ bakiye. - Koşul bozuksa bakiye değişmez, yalnızca bir mesaj yazılır.
- Bakiye hiçbir yoldan eksiye düşemez: bu, sınıfın değişmezidir.
Örnek: Banka Hesabı
BankaHesabi: Faiz
// ... // Faiz ekleme (yalnızca vadeli hesap) public void faizEkle(double oran) { if (hesapTuru.equals("Vadeli") && oran > 0) { double faiz = bakiye * oran / 100; bakiye += faiz; System.out.println("Faiz ekleniyor: " + faiz + " TL. Yeni bakiye: " + bakiye); } else if (!hesapTuru.equals("Vadeli")) { System.out.println( "Faiz yalnızca vadeli hesaplarda uygulanabilir."); } else { System.out.println("Geçersiz faiz oranı."); } }
- Faiz yalnızca vadeli hesapta ve pozitif oranla eklenir.
- Metinler
==ile değil,equalsile karşılaştırılır. faizbir yerel değişkendir: yalnızca metot çalışırken vardır, nesnenin parçası değildir.
Örnek: Banka Hesabı
BankaHesabi: Transfer
// ... // Başka bir hesaba transfer public void transfer(BankaHesabi hedefHesap, double miktar) { if (miktar <= bakiye && miktar > 0) { bakiye -= miktar; hedefHesap.paraYatir(miktar); System.out.println(miktar + " TL transfer edildi. Yeni bakiye: " + bakiye); } else { System.out.println( "Yetersiz bakiye veya geçersiz miktar."); } } }
transfer, aynı sınıftan başka bir nesnenin metodunu çağırır:hedefHesapüzerindeparaYatir.- Hedef hesabın
bakiyealanına doğrudan yazmak da mümkündü (aynı sınıf,privatesınıf düzeyindedir), ama metot çağırmak kuralların tek yerde kalmasını sağlar.
Örnek: Banka Hesabı · Adım adım kod izleme
İki Hesap, Bir Transfer: Adım Adım
Yapıcı çalışır: ilk nesne heap'te 2000.0 bakiye ile kurulur.
İkinci, bağımsız nesne. Her nesnenin kendi bakiye alanı vardır.
this = hesap1. miktar > 0 doğru: bakiye += miktar → 2500.0.
Bu kez this = hesap2. 200 ≤ 1500: bakiye 1300.0 olur; hesap1 etkilenmez.
Hesap vadeli: faiz = 2500.0 × 5 / 100 = 125.0, bakiye 2625.0.
transfer: koşul doğru, önce kendi bakiyesinden düşer: 2625.0 − 300.0 = 2325.0.
hedefHesap.paraYatir(miktar): yığında 3 çerçeve; şimdi this = hesap2, bakiye 1600.0.
paraYatir biter, transfer kaldığı yerden devam eder ve kendi mesajını yazar.
Getter'lar son bakiyeleri okur. Toplam para korunur: 2325 + 1600 = 3925 = 2625 + 1300.
// main içinde: BankaHesabi hesap1 = new BankaHesabi(123456, 2000.0, "Vadeli"); BankaHesabi hesap2 = new BankaHesabi(789012, 1500.0, "Vadesiz"); hesap1.paraYatir(500.0); hesap2.paraCek(200.0); hesap1.faizEkle(5.0); hesap1.transfer(hesap2, 300.0); System.out.println(hesap1.getBakiye()); System.out.println(hesap2.getBakiye());
Örnek: Banka Hesabı
Yapıcı da Doğrulamalı
- Setter'lar ve işlem metotları bakiyeyi korur; ama örnekteki yapıcı gelen değeri denetlemeden atar.
new BankaHesabi(1, -500.0, "Vadesiz")eksi bakiyeli bir hesap kurar;"vadeli"(küçük harf) yazılırsa hesap faiz alamaz ve kimse fark etmez.- Sınıf değişmezi nesnenin doğduğu anda sağlanmalıdır: yapıcı da bir ön koşul denetleyicisidir.
- Yapıcı istisna fırlatırsa
newifadesi hiçbir referans üretmez: geçersiz nesne kullanıcının eline hiç geçmez.
public BankaHesabi(int hesapNumarasi, double bakiye, String hesapTuru) { if (bakiye < 0) throw new IllegalArgumentException( "Başlangıç bakiyesi negatif olamaz"); if (!hesapTuru.equals("Vadeli") && !hesapTuru.equals("Vadesiz")) throw new IllegalArgumentException( "Bilinmeyen hesap türü: " + hesapTuru); this.hesapNumarasi = hesapNumarasi; this.bakiye = bakiye; this.hesapTuru = hesapTuru; }
Yapıcı, nesnenin kurulduğu tek kapıdır: kurallar orada bir kez uygulanırsa sınıfın öteki metotları gelen nesnenin geçerli olduğuna güvenebilir.
Örnek: Banka Hesabı · Adım adım kod izleme
Yapıcıda Doğrulama: Kod İzleme
300 geçerli: koşul yanlış, kelvin atanır ve a yeni nesneyi gösterir.
b açıkça null ile başlatılır; catch sonrasında da okunabilmesi için.
new ikinci nesneye yer ayırır (kelvin varsayılan 0.0) ve yapıcıyı çağırır. Parametre −5.0.
Ön koşul bozuk: throw yapıcıyı burada keser. Atama satırı hiç çalışmaz.
Kontrol catch bloğuna geçer. b = ... ataması yarıda kaldığı için b değişmedi; yarım nesneye ulaşan hiçbir referans yok.
Programda yalnızca geçerli Sicaklik nesneleri kullanılabilir: değişmez (kelvin ≥ 0) her nesnede doğrudur.
class Sicaklik { private final double kelvin; public Sicaklik(double kelvin) { if (kelvin < 0) throw new IllegalArgumentException( "Kelvin negatif olamaz"); this.kelvin = kelvin; } public double getKelvin() { return kelvin; } } // main içinde: Sicaklik a = new Sicaklik(300); Sicaklik b = null; try { b = new Sicaklik(-5); } catch (IllegalArgumentException e) { System.out.println("Reddedildi: " + e.getMessage()); } System.out.println(a.getKelvin() + " " + b);
Sınıf Tasarımı
Sınıf Tasarımı
- Sınıf tanımı iki kısma ayrılır: arayüz (interface) ve gerçekleme (implementation).
- Arayüz, sınıfın ne yaptığını ve nasıl kullanılacağını belirtir: public metotların adları, parametreleri, dönüş tipleri ve yorumları.
- Gerçekleme, sınıfın iç mekanik ayrıntılarını ve özel (private) alanlarını içerir. Bunlar yalnızca sınıfın içinde önemlidir.
- Gerçekleme değişse bile arayüz değişmeyebilir; öz alanlar sınıfın dışına gizlidir.
- Üç unsur: tanımlama (specification: yapıcı ve metotların imzaları), temsil (representation: veriyi tutan
privatealanlar) ve gerçekleme (implementation: yapıcı ve metot gövdeleri). Kullanıcı yalnızca tanımlamayı bilir; temsil ve gerçekleme değişse de kodu bozulmaz.
Sınıf Tasarımı
Arayüz
public interface Araba { // Sınıf arayüzü: NE yapılır? public void hareketEt(); public void dur(); }
- Java'da
interface, bir sınıfın ne yapacağını söyleyen sözleşmedir: metotların yalnızca imzası vardır, gövdesi yoktur. - Arabayı kullanan kişi yalnızca
hareketEt()vedur()metotlarını bilir.
Sınıf Tasarımı
Sınıf Gerçeklemesi
public class SporAraba implements Araba { // Sınıf gerçeklemesi: NASIL yapılır? private String marka; private int hiz; public SporAraba(String marka) { this.marka = marka; } public void hareketEt() { hiz = 100; System.out.println(marka + " hareket ediyor: " + hiz + " km/sa"); } public void dur() { hiz = 0; System.out.println(marka + " durdu."); } }
// main içinde: Araba araba = new SporAraba("Rüzgar"); araba.hareketEt(); araba.dur();
Rüzgar hareket ediyor: 100 km/sa Rüzgar durdu.
implements Araba: sınıf, arayüzdeki her metodu yazmak zorundadır.- Arayüz ile sınıf aynı pakette aynı adı taşıyamaz (
duplicate class: Araba); bu yüzden sınıfın adıSporAraba. AnadeğişkeniArabatipinde tanımlar: yalnızca arayüze bağımlıdır.
Sınıf Tasarımı
Gerçeklemeyi Değiştirmek
Eski: iki ayrı alan
public class DijitalSaat { private int dakika = 0; private int saniye = 0; public int getDakika() { return dakika; } public int getSaniye() { return saniye; } public void setDakika(int dakika) { if (dakika >= 0 && dakika < 60) { this.dakika = dakika; } } public void setSaniye(int saniye) { if (saniye >= 0 && saniye < 60) { this.saniye = saniye; } } }
Yeni: tek alan
public class DijitalSaat { // gece yarısından beri geçen saniye private int toplamSaniye = 0; public int getDakika() { return toplamSaniye / 60 % 60; } public int getSaniye() { return toplamSaniye % 60; } public void setDakika(int dakika) { if (dakika >= 0 && dakika < 60) { int fark = dakika - getDakika(); toplamSaniye += fark * 60; } } public void setSaniye(int saniye) { if (saniye >= 0 && saniye < 60) { toplamSaniye += saniye - getSaniye(); } } }
setDakika(12); setSaniye(45); setSaniye(75); sonrası iki sürüm de 12:45 verir.Sınıf Tasarımı · Adım adım kod izleme
Aynı Arayüz, Yeni Gerçekleme: Kod İzleme
Yeni sürüm tek bir alan tutar; eski sürüm (karşılaştırma için) iki alan. Dışarıdan ikisi de 00:00.
setDakika(12): fark 12 dakika, 12 · 60 = 720 saniye eklenir. Eski sürüm doğrudan dakika = 12 yazar.
setSaniye(45): değer aralıkta, koşul doğru.
Önce getSaniye() = 720 % 60 = 0; fark 45 eklenir: 765. Dışarıdan bakan için 12:45.
75 geçersiz: iki sürüm de reddeder. Kural (0–59) sınıfın içinde kaldı.
Fark negatif olabilir: 9 − 45 = −36, toplam 729. Dakika yine 12.
Çıktı 12:9; eski sürüm de aynısını verirdi. İç temsil değişti, main tek harf değişmedi.
private int toplamSaniye = 0; // tek alan public int getSaniye() { return toplamSaniye % 60; } public void setSaniye(int saniye) { if (saniye >= 0 && saniye < 60) toplamSaniye += saniye - getSaniye(); } // getDakika(): toplamSaniye / 60 % 60 DijitalSaat s = new DijitalSaat(); // main s.setDakika(12); s.setSaniye(45); s.setSaniye(75); s.setSaniye(9); System.out.println(s.getDakika() + ":" + s.getSaniye());
Sınıf Tasarımı
Tavsiyeler
- Sınıf içindeki tüm değişkenler (alanlar)
privatetanımlanmalı. - Değişkenlere erişim için gerektiği kadar
publicerişim metodu sağlanmalı (her alana otomatik setter yazmak şart değildir). - Her metodun nasıl kullanılacağını belirten yorum satırları eklenmeli: ne yapar, ön ve son koşulları neler.
- Yalnızca sınıf içinde kullanılan yardımcı metotlar
privatetanımlanmalı.
public class Ogrenci { private int not; private boolean gecerliMi(int deger) { return deger >= 0 && deger <= 100; } public void setNot(int not) { if (gecerliMi(not)) this.not = not; } }
Başka sınıftan o.gecerliMi(50) çağrılırsa:
error: gecerliMi(int) has private access in Ogrenci
Sınıf Tasarımı
Sor Değil, Söyle
Her alana bir getter ve bir setter yazmak sarmalama değildir: kurallar yine sınıfın dışında uygulanıyorsa veri yalnızca bir adım uzağa taşınmıştır.
Sormak: kural kullanan kodda
// her para çeken yerde aynı kontrol if (h.getBakiye() >= 300) { h.setBakiye(h.getBakiye() - 300); } // ...ve not ekleyen her yerde o.setNot(Math.min(100, o.getNot() + 5));
- Kural her çağrı yerinde tekrar eder; biri unutursa nesne bozulur.
setBakiyeyazıldığı anda herkes bakiyeyi istediği değere çekebilir.
Söylemek: kural nesnenin içinde
h.paraCek(300); // kural BankaHesabi'nda o.notEkle(5); // 100 sınırı Ogrenci'de
- Nesneye verisini sorup onun yerine karar vermek yerine, ne istendiği söylenir; kararı veriyi tutan nesne verir.
- Setter yalnızca alanın gerçekten serbestçe değişebildiği durumlarda yazılır.
BankaHesabi'nda bu yüzdensetBakiyeyoktur.
Sınama sorusu: “Bu kararı vermek için gereken veri kimde?” Cevap nesnenin kendisiyse karar da onun metodunda olmalıdır.
Sınıf Tasarımı
Sarmalamanın Faydaları
Nesne ile kullanıcısı arasındaki ilişkiyi sadeleştirir: kullanıcı yalnızca metotları bilir.
Nesneyi kullanıcının istenmeyen, hatalı erişimlerine karşı korur.
Arayüzü değiştirmeden sınıfın iç yapısı değiştirilebilir; kullanan kod etkilenmez.
Nesnenin durumu her zaman kurallara uyar (sınıf değişmezi, class invariant):
- yalnızca pozitif koordinatlı noktalar,
- saniye ve dakika 0–59 arasında,
- saat negatif olamaz.
setSaniye(75) reddedilir, paraCek bakiyeyi asla eksiye düşürmez, BankaHesabi'nın iç yapısı değişse bile paraYatir çağıran kod aynı kalır.Sınıf Tasarımı
Gözlemler
- Arayüzler, gerçeklemeye göre çok daha nadir değişir: bu, kodun kararlı olmasını sağlar.
- Gerçekleme değiştiğinde, ona doğrudan bağımlı olan kodların da değişmesi gerekir.
- Gerçeklemeyi gizlemek, diğer sınıfların bağımlılığını azaltır: değişiklik sınıfın içinde kalır (gevşek bağlılık, loose coupling).
Değiştirilemez Sınıflar
Sızan Referans
public class Karne { private final int[] notlar; public Karne(int[] notlar) { this.notlar = notlar; // aynı dizi } public int[] getNotlar() { return notlar; // iç dizi } public double ortalama() { int t = 0; for (int n : notlar) t += n; return (double) t / notlar.length; } }
int[] dizi = {70, 80, 90}; Karne k = new Karne(dizi); dizi[0] = 0; // dışarıdaki dizi k.getNotlar()[1] = -100; // getter'dan gelen System.out.println(k.ortalama());
-3.3333333333333335
- Alan
private final, setter yok; yine de notlar dışarıdan değişti, hatta −100 gibi geçersiz bir not girdi. - Sebep: dizi bir nesnedir. Yapıcı ve getter yalnızca referansı paylaştı; nesneye üç ayrı yerden ulaşılıyor.
finalyalnızca referansın başka diziyi göstermesini engeller, dizinin içeriğini korumaz.
Değiştirilemez Sınıflar · Adım adım kod izleme
Sızan Referans: Kod İzleme
Dizi heap'te bir nesnedir; dizi değişkeni yalnızca onun referansını tutar.
Yapıcı parametredeki referansı alana yazar. Artık Karne'nin private alanı ile main'in dizi değişkeni aynı diziyi gösterir.
dizi[0] = 0 Karne'nin hiçbir metodundan geçmez, ama Karne'nin gördüğü not değişti.
getNotlar() iç dizinin kendisini döndürür; dönen referansla −100 yazılır. Geçersiz not, hiçbir denetimden geçmeden nesneye girdi.
Ortalama (0 − 100 + 90) / 3 ≈ −3,33. private yazmak yetmedi: iç nesneye giden referans dışarı sızdı.
public Karne(int[] notlar) { this.notlar = notlar; } public int[] getNotlar() { return notlar; } // main içinde: int[] dizi = {70, 80, 90}; Karne k = new Karne(dizi); dizi[0] = 0; k.getNotlar()[1] = -100; System.out.println(k.ortalama());
Değiştirilemez Sınıflar
Savunmacı Kopyalama
public class Karne { private final int[] notlar; public Karne(int[] notlar) { this.notlar = notlar.clone(); // girişte } public int[] getNotlar() { return notlar.clone(); // çıkışta } // ortalama() aynı }
Aynı main ile
80.0
- Savunmacı kopya (defensive copy): değiştirilebilir bir nesne sınıfa girerken ve sınıftan çıkarken kopyalanır. İç diziye ulaşan tek referans sınıfın kendi alanı kalır.
- Yapıcıdaki kopya, çağıranın elindeki diziyi sonradan değiştirmesine karşı; getter'daki kopya, dönen diziyi değiştirmesine karşı korur.
- Listeler için
new ArrayList<>(liste)ya da salt okunur görünümCollections.unmodifiableList(liste)kullanılır. String,Integergibi değiştirilemez nesneler kopyalanmaz: paylaşılmaları zararsızdır.
Kopyalamanın bir maliyeti vardır; büyük veride salt okunur görünüm ya da baştan değiştirilemez bir tip seçmek daha ucuzdur.
Değiştirilemez Sınıflar
Değiştirilemez Sınıf Tasarlamak
public final class Para { // alt sınıf yok private final long kurus; // bir kez atanır private final String birim; public Para(long kurus, String birim) { this.kurus = kurus; this.birim = birim; } public Para ekle(Para diger) { // setter yerine if (!birim.equals(diger.birim)) throw new IllegalArgumentException("Birim farklı"); return new Para(kurus + diger.kurus, birim); } @Override public String toString() { return kurus / 100 + "," + String.format("%02d", kurus % 100) + " " + birim; } }
Kurallar
- Setter yok; durum yalnızca yapıcıda kurulur.
- Alanlar
private final. - Sınıf
final: değiştirilebilir bir alt sınıf yazılamasın. - “Değiştiren” metotlar yeni bir nesne döndürür.
- Değiştirilebilir alanlar varsa savunmacı kopya.
Kazanç
- Değişmez yalnızca yapıcıda denetlenir; sonra hiç bozulamaz.
- Nesne kopyalanmadan paylaşılabilir,
HashMapanahtarı olabilir, iş parçacıkları arasında güvenlidir. Stringverecordbu kuralların hazır örnekleridir.
Değiştirilemez Sınıflar · Adım adım kod izleme
Değiştirilemez Para: Kod İzleme
İlk nesne kurulur. Alanları final: bundan sonra hiçbir metot onları değiştiremez.
ekle, a'yı değiştirmez; toplamı taşıyan yeni bir nesne (#3) kurup döndürür.
Dönen değer bir değişkene atanmadı: #3 kaybolur. Değiştirilemez nesnelerde en sık yapılan hata budur; a değişmedi.
Bu kez sonuç b'ye atanır: 1250 + 375 = 1625 kuruş. Argüman olarak kurulan #4 de artık kullanılmaz.
a ilk değerini korudu. String'in toUpperCase() ya da concat() metotları da aynı biçimde çalışır.
public Para ekle(Para diger) { if (!birim.equals(diger.birim)) throw new IllegalArgumentException( "Birim farklı"); return new Para(kurus + diger.kurus, birim); } // main içinde: Para a = new Para(1250, "TL"); a.ekle(new Para(100, "TL")); // sonuç atıldı Para b = a.ekle(new Para(375, "TL")); System.out.println(a + " | " + b);
Paketler
Paketler
- Paket (package): bir klasör içinde gruplanmış sınıflar topluluğu. Klasörün adı paketin adıdır.
- Her
publicsınıf ayrı bir dosyada, sınıfla aynı adlı dosyada tanımlanır. - Dosyanın ilk satırı ait olduğu paketi bildirir:
package paket_adi; - Derleyici ve JVM paketleri sınıf yolu (classpath) köklerinden başlayarak arar; paket adı bu kökten itibaren klasör yolunu söyler. Varsayılan sınıf yolu bulunulan dizindir (
.). - İç içe klasörlerde
/veya\yerine nokta kullanılır:okul/yonetim→okul.yonetim. - Paket adları küçük harfle yazılır; Java'nın kendi paketleri:
java.lang,java.util,java.io…
proje/ ├── src/ │ ├── banka/ │ │ ├── Hesap.java // package banka; │ │ └── Yardimci.java // package banka; │ └── uygulama/ │ └── Ana.java // package uygulama; └── out/ // derleme çıktısı ├── banka/ │ ├── Hesap.class │ └── Yardimci.class └── uygulama/ └── Ana.class
Sınıfın tam adı paketini de içerir: banka.Hesap, uygulama.Ana.
Paketler
Paket Örneği
package banka; public class Hesap { private double bakiye; public void yatir(double miktar) { if (miktar > 0) { bakiye += miktar; } } public double getBakiye() { return bakiye; } }
package uygulama; import banka.Hesap; public class Ana { public static void main(String[] args) { Hesap h = new Hesap(); h.yatir(250.0); System.out.println("Bakiye: " + h.getBakiye()); } }
> javac -d out src/banka/Hesap.java src/uygulama/Ana.java > java -cp out uygulama.Ana Bakiye: 250.0
-d out: .class dosyaları paket klasörleriyleout/altına yazılır.-cp out: sınıf yolu; çalıştırırken sınıfın tam adı verilir.
Paketler
İçe Aktarma (import)
- Başka paketteki bir sınıfı kısa adıyla kullanmak için:
import paket_adi.SinifAdi;Paketin tümü:import java.util.*;(alt paketler hariç). importyazmadan tam ad da kullanılabilir:java.util.Random.java.lang(String,Math,System) ve aynı paketteki sınıflar otomatik görünür.- Sıra: önce
package, sonraimport'lar, sonra sınıf.import staticstatic üyeyi sınıf adı olmadan kullandırır.
import java.util.Scanner; import static java.lang.Math.sqrt; public class ImportOrnek { public static void main(String[] args) { Scanner giris = new Scanner(System.in); int sayi = giris.nextInt(); java.util.Random rastgele = new java.util.Random(42); System.out.println(sqrt(sayi) + " " + Math.max(sayi, 10) + " " + rastgele.nextInt(100)); } }
7.0 49 30
Scanner: import ile kısa ad.java.util.Random: tam ad, import yok.sqrt:import static;Math.max:java.lang.
Paketler
Paket Erişimi
package banka; class Yardimci { // public değil static double kdv(double tutar) { return tutar * 0.20; } }
package uygulama; import banka.Yardimci; public class Ana2 { }
Ana2.java:3: error: Yardimci is not public in banka;
cannot be accessed from outside package
import banka.Yardimci;
^- Belirleyicisi olmayan sınıf ve üyeler paket erişimlidir: yalnızca kendi paketinden görülür.
Yardimci,bankapaketinin iç işidir;Hesaponu kullanabilir,uygulamapaketi kullanamaz.- Paket de bir sarmalama düzeyidir: sınıflar dışarıya kapatılır, yalnızca
publicolanlar paketin arayüzünü oluşturur.
Paketler
Paket Adlandırma ve Alt Paketler
- Ad çakışmasını önlemek için kurumlar paket adına ters çevrilmiş alan adıyla başlar:
giresun.edu.tr→tr.edu.giresun.banka. - Noktalı adlar klasörlere karşılık gelir:
tr/edu/giresun/banka/. - Alt paket ayrı bir pakettir.
tr.edu.giresun.banka.rapor,banka'nın paket erişimli üyelerini göremez; adların benzemesi bir erişim hakkı vermez. import tr.edu.giresun.banka.*;alt paketleri içe aktarmaz:import java.util.*;dajava.util.function'daki sınıfları getirmez.
// tr/edu/giresun/banka/Yardimci.java package tr.edu.giresun.banka; class Yardimci { // paket erişimli static double kdv(double t) { return t * 0.20; } }
// tr/edu/giresun/banka/rapor/Rapor.java package tr.edu.giresun.banka.rapor; import tr.edu.giresun.banka.Yardimci; public class Rapor { double hesapla() { return Yardimci.kdv(100); } }
error: Yardimci is not public in tr.edu.giresun.banka; cannot be accessed from outside package
Paket adı ile klasör yolu birebir eşleşmezse derleyici sınıfı bulamaz; bu yüzden IDE'ler klasörleri paket adından oluşturur.
Paketler
Sınıf Adı Çakışmaları
import java.util.*; import java.sql.*; public class Belirsiz { public static void main(String[] args) { Date tarih = null; } }
Belirsiz.java:6: error: reference to Date is ambiguous both class java.sql.Date in java.sql and class java.util.Date in java.util match
import java.util.Date; public class TarihOrnegi { public static void main(String[] args) { Date baslangic = new Date(0); // java.util java.sql.Date kayit = // tam ad java.sql.Date.valueOf("2024-09-16"); System.out.println(baslangic.getTime()); System.out.println(kayit); } }
0 2024-09-16
- İki farklı paketteki sınıflar aynı adı taşıyabilir:
java.util.Datevejava.sql.Date. - Belirsizliği gidermek için paket adı kullanılır: biri
importedilir, diğeri tam adıyla yazılır.
Özet
Özet
| Kavram | Anlamı | Java'da |
|---|---|---|
| Sarmalama | Veri + metotları tek birimde toplamak, iç ayrıntıyı gizlemek | private alanlar, public metotlar |
| Bilgi saklama | “Ne” ile “nasıl”ı ayırmak | Kullanıcı yalnızca metot imzasını bilir |
| Ön / son koşul | Çağrıdan önce varsayılan / sonra garanti edilen durum | Javadoc yorumu + if kontrolü |
| Erişim belirleyici | Kimin erişebileceği | public, protected, (paket), private |
| Getter / setter | Alanı okuyan / doğrulayarak değiştiren metot | getSaniye(), setSaniye(int), this.saniye = saniye |
| Arayüz / gerçekleme | Sınıfın dış yüzü / iç mekanizması | interface Araba, class SporAraba implements Araba |
| Paket, import | Klasördeki sınıf grubu; başka paketten kısa adla kullanım | package banka;, import java.util.Scanner; |
| Sınıf adı çakışması | Farklı paketlerde aynı adlı sınıf | Tam ad: java.sql.Date |
Özet
İlgili Sayfalar
Simülatör: public, protected, paket erişimi ve private üyelere hangi sınıftan erişilebildiği; setter ile korunan alan.
Bilgi saklama, sözleşme, erişim düzeyleri, getter ve setter, banka hesabı, gerçeklemeyi değiştirmek ve paket soruları.
Özet
Sık Yapılan Hatalar (1)
error: saniye has private access in DijitalSaats.saniye = 75; yerine s.setSaniye(75); yazılır.
en = en; // derlenir, alan değişmezParametre alanı gölgeler; getEn() 0 döndürür. Doğrusu this.en = en;
error: incompatible types: unexpected return valuepublic void getEn() değer döndüremez; dönüş tipi int olmalı.
public void setSaniye(int s) { saniye = s; }Bu, alanı public yapmaktan farksızdır; geçerlilik kuralı setter'da denetlenir.
Özet
Sık Yapılan Hatalar (2)
error: cannot find symbol symbol: class ScannerDosyanın başına import java.util.Scanner; eklenir.
error: class Hesap is public, should be declared in a file named Hesap.javaDosya adı, public sınıfın adıyla birebir aynı olmalı.
error: Yardimci is not public in banka; cannot be accessed from outside packageSınıf ya public yapılır ya da yalnız aynı paketten kullanılır.
error: SporAraba is not abstract and does not override abstract method dur() in Arabaimplements eden sınıf arayüzdeki tüm metotları yazmalıdır.
Özet
Sık Yapılan Hatalar (3)
return notlar; değiştirilebilir diziyi ya da listeyi dışarı açar. Kopya ya da salt okunur görünüm döndürülür.
private final int[] notlar: referans sabittir, dizinin elemanları değil.
a.ekle(p); ya da s.toUpperCase(); tek başına hiçbir şeyi değiştirmez: a = a.ekle(p);
Setter'lar denetlese de new BankaHesabi(1, -500.0, ...) geçersiz nesne kurar. Yapıcı da kuralı uygulamalı.
-ea verilmezse denetim hiç çalışmaz. public metot argümanları için IllegalArgumentException.
import java.util.*; sonrası Function için: cannot find symbol. java.util.function ayrıca içe aktarılır.
Kural kullanan koda kayar. Önce davranış (paraCek, notEkle) tasarlanır; setter gerekmeyebilir.
Geçersiz değeri hiçbir iz bırakmadan yok saymak hatayı gizler; ya sözleşmede belirtilir ya da istisna fırlatılır.
Özet
Örnek Problemler (1)
DijitalSaat t = new DijitalSaat();
t.setSaat(25);
t.setDakika(30);
t.setSaniye(-1);
t.setSaniye(59);
t.goster();DijitalSaat a = new DijitalSaat(); DijitalSaat b = a; a.setDakika(15); b.setDakika(45); b = new DijitalSaat(); b.setDakika(10); System.out.println(a.getDakika() + " " + b.getDakika());
“Erişim Metotları” slaytındaki DijitalSaat sınıfı kullanılıyor (saat 0–23, dakika/saniye 0–59).
- Soldaki kod ne yazdırır?
- Sağdaki kod ne yazdırır? Kaç tane
DijitalSaatnesnesi oluşturuldu?
Cevapları göster
- 00:30:59. 25 ve −1 setter'larca reddedilir; saat başlangıç değeri 0'da kalır.
- 45 10.
b = ayeni nesne oluşturmaz, iki değişken aynı nesneyi gösterir; 45 onun dakikasıdır. Sonrabikinci nesneye bağlanır. Toplam 2 nesne.
Özet
Örnek Problemler (2)
public class Test { public static void main(String[] args) { DijitalSaat s = new DijitalSaat(); s.setSaniye(30); // A int x = s.saniye; // B System.out.println(s.getSaniye()); // C s.getSaniye() = 10; // D s.setSaniye("40"); // E } }
A–E satırlarından hangileri derleme hatası verir? Neden?
Cevapları göster
- B:
saniye has private access in DijitalSaat. Okumak içins.getSaniye(). - D:
unexpected type, required: variable, found: value. Metot çağrısı bir değerdir, atama yapılamaz;s.setSaniye(10)yazılmalı. - E:
incompatible types: String cannot be converted to int. - A ve C doğrudur: public metotlar çağrılıyor.
Özet
Örnek Problemler (3)
BankaHesabi h = new BankaHesabi(111, 1000.0, "Vadesiz"); h.paraCek(5000.0); h.paraYatir(-50.0); h.faizEkle(3.0); h.paraCek(250.0); BankaHesabi v = new BankaHesabi(222, 100.0, "Vadeli"); h.transfer(v, 1000.0); h.transfer(v, 750.0); System.out.println(h.getBakiye() + " " + v.getBakiye());
BankaHesabi sınıfıyla bu kod ne yazdırır? Son satırda hangi bakiyeler görülür?
Cevabı göster
Yetersiz bakiye. Yatırılan miktar geçersiz. Faiz yalnızca vadeli hesaplarda uygulanabilir. 250.0 TL çekildi. Kalan bakiye: 750.0 Yetersiz bakiye veya geçersiz miktar. 750.0 TL yatırıldı. Yeni bakiye: 850.0 750.0 TL transfer edildi. Yeni bakiye: 0.0 0.0 850.0
Özet
Örnek Problemler (4)
A) Kopyalamayan Karne ile
int[] d = {50, 60}; Karne k = new Karne(d); int[] g = k.getNotlar(); g[0] = 100; d[1] = 100; System.out.println(k.ortalama());
B) Para sınıfıyla
Para p = new Para(100, "TL"); p.ekle(p); p = p.ekle(p); p.ekle(new Para(1, "TL")); System.out.println(p);
- A ne yazdırır? Savunmacı kopyalı
Karneile ne yazdırır? - B ne yazdırır?
- On kez
arttir()çağıranSayacprogramı-eaolmadan ve-eaile çalıştırılırsa ne olur? Hangisi hatayı gösterir? Kesirdışındaki bir sınıftanew Kesir(1, 2).payderlenir mi?
Cevapları göster
- 100.0:
d,gve alan aynı diziyi gösterir; iki atama da nesneye ulaşır. Kopyalı sürümde 55.0: iki atama da kopyalara yapılır. - 2,00 TL: yalnızca
p = p.ekle(p)sonucu saklanır (100 + 100); öteki iki çağrının sonucu atılır. -eaolmadan bitti yazar, hata görünmez.-eaile onuncu artırmadaAssertionError: deger=10.- Hayır:
pay has private access in Kesir.privateerişim yalnızcaKesir'in kendi kodunda serbesttir.
Özet
Alıştırmalar (1)
Ogrenci:privateadvenot; not yalnızca 0–100 arası kabul edilsin;gectiMi()not ≥ 50 isetruedöndürsün.Nokta: yalnızca negatif olmayan koordinatları kabul etsin;uzaklik()orijine uzaklığı döndürsün.Termometre: santigrat değeri saklasın (−273.15 altını reddetsin);getFahrenheit()ayrı bir alan olmadan hesaplasın.
Cevaplar / ipuçları
if (not >= 0 && not <= 100) this.not = not;→setNot(120)sonrası “0 false”,setNot(75)sonrası “75 true”.- Yapıcı setter'ları çağırsın;
return Math.sqrt(x * x + y * y);→new Nokta(3, 4): 5.0;setX(-7)reddedilir, x = 3 kalır. return santigrat * 9 / 5 + 32;→ 25 °C = 77.0 °F. Türetilen değer ayrı alanda tutulmaz;setSantigrat(-300)sonrası değer 25.0 kalır.
Özet
Alıştırmalar (2)
Sayac: yalnızcaarttir(),sifirla(),getDeger()metotları olsun. Neden setter yok?Ogrenci'yiokulpaketine taşıyın,uygulama.Ana'dan kullanın; derleme ve çalıştırma komutlarını yazın.BankaHesabi'na yalnızca getter'ı olanislemSayisiekleyin; başarılı her yatırma/çekmede 1 artsın. Banka örneğinin (izleme slaytı) sonunda iki hesabın değeri ne olur?
Cevaplar / ipuçları
- Değer yalnızca 1'er artmalı veya sıfırlanmalı;
setDegerbu kuralı delerdi. Üçarttir()→ 3,sifirla()→ 0. package okul;veimport okul.Ogrenci;→javac -d out src/okul/Ogrenci.java src/uygulama/Ana.java,java -cp out uygulama.Ana.- hesap1: 1 (yalnızca
paraYatir; faiz ve transfer kendiparaCek'ini çağırmaz), hesap2: 2 (paraCek+ transferdekiparaYatir).
Özet
Kaynaklar
- Oracle, The Java Tutorials: "Controlling Access to Members of a Class", "Using the this Keyword", "Packages", "Interfaces".
- J. Gosling ve diğ., The Java Language Specification, Java SE 21 Edition (6.6 Access Control, 7 Packages and Modules, 7.5 Import Declarations, 15.12.2 metot seçimi).
- P. Deitel ve H. Deitel, Java: How to Program, Early Objects, 11. baskı, Pearson, 2017 (Bölüm 3 ve 8: Classes and Objects).
- K. Sierra ve B. Bates, Head First Java, 3. baskı, O'Reilly, 2022 (Bölüm 4: encapsulation).
- C. S. Horstmann, Core Java, Volume I: Fundamentals, 12. baskı, 2022 (Bölüm 4: Objects and Classes).
- J. Bloch, Effective Java, 3. baskı, Addison-Wesley, 2018 (Madde 15–16: erişimi en aza indirmek, public alan yerine erişim metodu).
- A. B. Downey ve C. Mayfield, Think Java, 2. baskı, O'Reilly, 2019 (Bölüm 11: Designing Classes).