Bölüm 4: 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; metot ve 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 · Kodu adım adım çalıştır
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.
Erişim Belirleyiciler
Erişim Belirleyiciler
- Erişim belirleyici (access modifier): bir sınıfa, alana veya metoda kimin erişebileceğini belirleyen anahtar kelime.
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 nitelikleri (alanları) genellikle
privatetanımlanır. - Niteliklere 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; ayrıntısı Kalıtım bölümündedir.- En kısıtlayıcı olanı seçin: ö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 (sonraki slayt).- 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.
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 (okuyucu): 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 · Kodu adım adım çalıştır
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 okuyucuisile 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ı/türü 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şmez sınıflar için record Nokta(int x, int y) { } yazılabilir; alanlar otomatik private final olur, okuyucular x() ve y() adını alır.
Getter ve Setter
Deneyin: Setter Koruması
“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; } // ... işlemler sonraki slaytlarda
- Üç 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. - Sonraki slayt bu çağrıları adım adım izler.
Örnek: Banka Hesabı · Kodu adım adım çalıştır
İ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());
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çekleştirim (implementation).
- Arayüz, sınıfın ne yaptığını ve nasıl kullanılacağını belirtir: public metotların adları, parametreleri, dönüş türleri ve yorumları.
- Gerçekleştirim, sınıfın iç mekanik ayrıntılarını ve özel (private) niteliklerini içerir. Bunlar yalnızca sınıfın içinde önemlidir.
- Gerçekleştirim değişse bile arayüz değişmeyebilir; öz nitelikler sınıfın dışına gizlidir.
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. - Arayüzler ayrıntılı olarak Soyut Sınıflar bölümünde ele alınır.
Sınıf Tasarımı
Sınıf Gerçekleştirimi
public class SporAraba implements Araba { // Sınıf gerçekleştirimi: 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şkeniArabatüründe tanımlar: yalnızca arayüze bağımlıdır.
Sınıf Tasarımı
Gerçekleştirimi 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ı
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ı
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çekleştirimden çok daha nadir değişir: bu, kodun kararlı olmasını sağlar.
- Gerçekleştirim değiştiğinde, ona doğrudan bağımlı olan kodların da değişmesi gerekir.
- Gerçekleştirimi 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).
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 staticstatik ü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.
Ad Çakışmaları
Metot Adı Çakışmaları
public class Yazici { static void yazdir(int x) { System.out.println("int: " + x); } static void yazdir(double x) { System.out.println("double: " + x); } static void yazdir(String s) { System.out.println("String: " + s); } static void yazdir(int a, int b) { System.out.println("iki int: " + a + ", " + b); } public static void main(String[] args) { yazdir(7); // int: 7 yazdir(7.5); // double: 7.5 yazdir("yedi"); // String: yedi yazdir(3, 4); // iki int: 3, 4 yazdir('A'); // int: 65 (char → int) yazdir(5L); // double: 5.0 (long → double) yazdir(2.5f); // double: 2.5 (float → double) } }
- Aynı adlı birden fazla metot olabilir (aşırı yükleme, overloading); parametre sayısı ve türleri ayırt eder. (Yorumlar gerçek çıktıdır.)
- Tam eşleşme yoksa genişletme dönüşümü denenir:
char→int,long→double.
- Hiçbiri uymazsa derleme hatası:
yazdir(true)→no suitable method found for yazdir(boolean) - Dönüş türü tek başına ayırt etmez; parametre listesi farklı olmalıdır.
Ad Çakışmaları
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: birini
importedin, diğerini tam adıyla yazın.
Ö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çekleştirim | 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; |
| Ad çakışması | Aynı adlı metot / sınıf | Parametre listesi / tam ad java.sql.Date |
Özet
Sık Yapılan Hatalar (1)
error: saniye has private access in DijitalSaats.saniye = 75; yerine s.setSaniye(75); kullanın.
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üş türü int olmalı.
public void setSaniye(int s) { saniye = s; }Bu, alanı public yapmaktan farksızdır; geçerlilik kuralını setter'a koyun.
Özet
Sık Yapılan Hatalar (2)
error: cannot find symbol symbol: class ScannerDosyanın başına import java.util.Scanner; ekleyin.
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 packageYa sınıfı public yapın ya da aynı pakette kullanın.
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
Ö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
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).