Bölüm 4: Soyut Sınıflar ve Arayüzler

Bölüm 4: Soyut Sınıflar ve Arayüzler · Çalışma Soruları
SoyutlamaSoyut sınıf ve metotŞablon metotArayüz ve implementsdefault / static / privateMühürlü tiplerArayüz mü, soyut sınıf mı?
Sercan KÜLCÜ

Çoktan Seçmeli · Soyutlama

Soru 1: Soyutlamanın Amacı

Java’da soyut sınıflar ve arayüzler ortak olarak neyi sağlar?

B: İkisi de soyutlama aracıdır: “ne”yi (metot imzalarını, sözleşmeyi) yukarıda tanımlar, “nasıl”ı alt sınıflara ya da gerçekleştiren sınıflara bırakır. Sınıflarda çoklu kalıtım yoktur (A); ikisinden de new ile nesne oluşturulamaz; çağrılar yine dinamik bağlanır (D).

Çoktan Seçmeli · Soyut Sınıflar

Soru 2: Hangisi Derlenir?

Aşağıdaki tek satırlık tanımlardan hangisi derlenir?

C: Hiç soyut metodu olmayan soyut sınıf geçerlidir (yine de new A() yazılamaz). A: abstract methods cannot have a body. B ve D: illegal combination of modifiers; private ve final geçersiz kılmayı engeller, soyut metot ve soyut sınıf ise alt sınıf için vardır.

Hata Bulma · Soyut Sınıflar

Soru 3: Alan() ≠ alan()

Hangi satırlar derleme hatası verir? Her biri nasıl düzeltilir?

abstract class Sekil {
  String ad;
  Sekil(String ad) { this.ad = ad; }
  abstract double alan();
}
class Kare extends Sekil {
  double k;
  Kare(double k) { super("Kare"); this.k = k; }
  double Alan() { return k * k; }
}
// main içinde:
Sekil s = new Sekil("?");
Sekil[] d = new Sekil[2];
Cevabı göster
  • class Kare: Kare is not abstract and does not override abstract method alan() in Sekil. Alan() (büyük A) yeni bir metottur; soyut alan() hâlâ eksik. Ad düzeltilmeli; üstüne @Override yazılırsa bu tür yazım hataları hemen yakalanır.
  • new Sekil("?"): Sekil is abstract; cannot be instantiated. Somut alt sınıf kullanılır: Sekil s = new Kare(3);
  • new Sekil[2] derlenir: nesne değil, iki boş (null) referans oluşturur. Soyut sınıfın yapıcısı olması da geçerlidir.

Adım Adım Çalıştırma · Soyut Sınıflar

Soru 4: Soyut Tip, Somut Nesne

Soyut sınıfın yapıcısı ve somut ozet() metodu var. Program ne yazar?

Sekil (static)adet1YığınHeapSekil(String)ad"Kare"Kare(double)k2.0main()d?#1 Karead"Kare"k2.0

new Kare(2): Kare yapıcısı super("Kare") ile soyut sınıfın yapıcısını çağırır. Ayrı bir Sekil nesnesi oluşmaz; aynı nesnenin Sekil kısmı kurulur. adet = 1.

Sekil (static)adet2YığınHeapmain()d[0]d[1]#1 Karead"Kare"k2.0#2 Dairead"Daire"r1.0

İkinci nesne de aynı yoldan kurulur (adet = 2). Dizinin öğe tipi soyut Sekil, gösterdikleri somut nesneler.

Sekil (static)adet2YığınHeapozet()thismain()d[0]d[1]s#1 Karead"Kare"k2.0#2 Dairead"Daire"r1.0

ozet() somut, Sekil’den gelir. İçindeki alan() soyut; this bir Kare → Kare.alan(): 4.0.

Sekil (static)adet2YığınHeapozet()thismain()d[0]d[1]s#1 Karead"Kare"k2.0#2 Dairead"Daire"r1.0

Aynı satır, farklı nesne: bu kez Daire.alan() = 3 · 1 · 1 = 3.0. Soyut sınıftaki kod, alt sınıfın yazdığı metodu çağırır.

Sekil (static)adet2YığınHeapmain()d[0]d[1]#1 Karead"Kare"k2.0#2 Dairead"Daire"r1.0

static sayaç iki yapıcı çağrısını saydı: 2.

abstract class Sekil {
  static int adet = 0;
  String ad;
  Sekil(String ad) { this.ad = ad; adet++; }
  abstract double alan();
  String ozet() { return ad + ":" + alan(); }
}
class Kare extends Sekil {
  double k;
  Kare(double k) { super("Kare"); this.k = k; }
  double alan() { return k * k; }
}
class Daire extends Sekil {
  double r;
  Daire(double r) { super("Daire"); this.r = r; }
  double alan() { return 3 * r * r; }
}
// main içinde:
Sekil[] d = { new Kare(2), new Daire(1) };
for (Sekil s : d) System.out.println(s.ozet());
System.out.println(Sekil.adet);

Çıktı Sorusu · Soyut Sınıflar

Soru 5: Çay mı, Kahve mi?

Program ne yazar? Cay’da final hazirla() geçersiz kılınmak istense ne olur?

abstract class Icecek {
  final void hazirla() {
    System.out.print("su ");
    demle();
    if (sut()) System.out.print("süt ");
    System.out.println("servis");
  }
  abstract void demle();
  boolean sut() { return false; }
}
class Cay extends Icecek {
  void demle() { System.out.print("çay "); }
}
class Kahve extends Icecek {
  void demle() { System.out.print("kahve "); }
  @Override boolean sut() { return true; }
}
// main: new Cay().hazirla();
//       Icecek i = new Kahve(); i.hazirla();
Cevabı göster
su çay servis
su kahve süt servis
  • İskelet (sıra) soyut sınıfta, değişen adım alt sınıfta: şablon metot.
  • demle() her nesnede kendi sınıfının sürümüyle çalışır. sut() bir “kanca”dır: yalnızca Kahve onu geçersiz kılar.
  • final metot geçersiz kılınamaz: hazirla() in Cay cannot override hazirla() in Icecek; overridden method is final. Alt sınıflar sırayı bozamaz.

Çoktan Seçmeli · Arayüzler

Soru 6: Arayüzde Alan

interface GeometrikSekil { int KENAR_SAYISI = 4; void ciz(); } için hangisi doğrudur?

A: Arayüzde alan olarak yalnızca sabit tanımlanır: örtük public static final. GeometrikSekil.KENAR_SAYISI = 5; → cannot assign a value to static final variable; değer vermemek → = expected. Gövdesiz metotlar örtük public abstract’tır (C).

Çoktan Seçmeli · Arayüzler

Soru 7: public Unutulursa

class Kare implements GeometrikSekil { void ciz() { } } yazıldı. Ne olur?

D: Arayüz metodu örtük public’tir; gerçekleştiren metot erişimi daraltamaz: ciz() in Kare cannot implement ciz() in GeometrikSekil; attempting to assign weaker access privileges; was public. Doğrusu public void ciz().

Adım Adım Çalıştırma · Arayüzler

Soru 8: Arayüz Tipinde Sepet

Üç ilgisiz sınıf aynı arayüzü gerçekleştiriyor. Döngü sonunda toplam ve en pahalı ürünün fiyatı nedir?

YığınHeapmain()sepettoplam0.0enPahalif?#0 Fiyatli[][0][1][2]#1 Kitap#2 Kalemadet4#3 Bilet

Dizinin öğe tipi bir arayüz; öğeler üç ilgisiz sınıfın nesnelerini gösterir. Ortak noktaları yalnızca Fiyatli sözleşmesi.

YığınHeapmain()sepettoplam40.0enPahalif#0 Fiyatli[][0][1][2]#1 Kitap#2 Kalemadet4#3 Bilet

f → Kitap: Kitap.fiyat() = 40.0. 40 > 40 yanlış; en pahalı değişmez.

YığınHeapmain()sepettoplam70.0enPahalif#0 Fiyatli[][0][1][2]#1 Kitap#2 Kalemadet4#3 Bilet

f → Kalem: 7.5 × 4 = 30.0; toplam 70.0. 30 > 40 yanlış.

YığınHeapmain()sepettoplam95.0enPahalif#0 Fiyatli[][0][1][2]#1 Kitap#2 Kalemadet4#3 Bilet

f → Bilet: 25.0; toplam 95.0. Aynı çağrı, her turda başka bir sınıfın metodu (dinamik bağlama).

YığınHeapmain()sepettoplam95.0enPahalif?#0 Fiyatli[][0][1][2]#1 Kitap#2 Kalemadet4#3 Bilet

Çıktı: 95.0 40.0. Yeni bir Fiyatli sınıfı eklemek için döngü değişmez.

interface Fiyatli { double fiyat(); }
class Kitap implements Fiyatli {
  public double fiyat() { return 40; }
}
class Kalem implements Fiyatli {
  int adet;
  Kalem(int adet) { this.adet = adet; }
  public double fiyat() { return 7.5 * adet; }
}
class Bilet implements Fiyatli {
  public double fiyat() { return 25; }
}
// main içinde:
Fiyatli[] sepet = { new Kitap(), new Kalem(4),
                    new Bilet() };
double toplam = 0;
Fiyatli enPahali = sepet[0];
for (Fiyatli f : sepet) {
  toplam += f.fiyat();
  if (f.fiyat() > enPahali.fiyat()) enPahali = f;
}
System.out.println(toplam + " " + enPahali.fiyat());

Adım Adım Çalıştırma · Arayüz Metotları

Soru 9: default Metot ve Geçersiz Kılma

ikiKez() arayüzde bir kez yazılmış. İki nesnede kaç artış yapar? Program ne yazar?

YığınHeapmain()ab#1 Basitd0#2 Ciftlid0

İki nesne, ikisi de Sayac tipinde referanslarla tutuluyor. Ciftli, d alanını Basit’ten alır (private, yalnızca metotlarla erişilir).

YığınHeaparttir()thisikiKez()thismain()ab#1 Basitd1#2 Ciftlid0

ikiKez() arayüzün default metodu; Basit yazmadığı için o çalışır. İçindeki arttir() = this.arttir() → Basit’in sürümü: d = 1.

YığınHeaparttir()thisikiKez()thismain()ab#1 Basitd2#2 Ciftlid0

İkinci çağrı: d = 2.

YığınHeapCiftli.arttir()thisikiKez()thismain()ab#1 Basitd2#2 Ciftlid2

Aynı default metot, ama this bir Ciftli: geçersiz kılınmış arttir() iki kez super.arttir() yapar → d = 2.

YığınHeapCiftli.arttir()thisikiKez()thismain()ab#1 Basitd2#2 Ciftlid4

İkinci arttir(): d = 4.

YığınHeapmain()ab#1 Basitd2#2 Ciftlid4

sifirMi() de default: deger() 4, sıfır değil. Çıktı: 2 4 false.

interface Sayac {
  int deger();
  void arttir();
  default boolean sifirMi() { return deger() == 0; }
  default void ikiKez() { arttir(); arttir(); }
}
class Basit implements Sayac {
  private int d;
  public int deger() { return d; }
  public void arttir() { d++; }
}
class Ciftli extends Basit {
  @Override public void arttir() {
    super.arttir(); super.arttir();
  }
}
// main içinde:
Sayac a = new Basit();
Sayac b = new Ciftli();
a.ikiKez();
b.ikiKez();
System.out.println(a.deger() + " " + b.deger()
    + " " + b.sifirMi());

Çoktan Seçmeli · Arayüz Metotları

Soru 10: Arayüzün static Metodu

interface Hesap { static int topla(int a, int b) { return a + b; } } ve class Basit implements Hesap { } var. Hesap.topla(3, 4) ile Basit.topla(3, 4) için hangisi doğrudur?

A: Arayüzün static metotları gerçekleştiren sınıfa kalıtımla geçmez; yalnızca arayüz adıyla çağrılır. Basit.topla → cannot find symbol. (Sınıflardaki static metotlar ise alt sınıf adıyla da çağrılabilir.)

Çıktı Sorusu · Arayüz Metotları

Soru 11: İki default selam()

İki arayüz aynı imzalı default metot getiriyor. Program ne yazar? Gorevli’de selam() hiç yazılmasaydı ne olurdu?

// p(s): System.out.println(s)
interface Selamlayan {
  default void selam() { p("Merhaba"); }
}
interface Karsilayan {
  default void selam() { p("Hoş geldiniz"); }
}
class Gorevli implements Selamlayan, Karsilayan {
  public void selam() {
    Karsilayan.super.selam();
    p("Ben Görevli");
  }
}
// main içinde:
Selamlayan s = new Gorevli();
s.selam();
Cevabı göster
Hoş geldiniz
Ben Görevli
  • Referans Selamlayan tipinde olsa da nesne Gorevli: onun selam()’ı çalışır.
  • Karsilayan.super.selam() yalnızca o arayüzün default sürümünü çağırır; Merhaba hiç yazılmaz.
  • selam() yazılmasaydı derlenmezdi: class Gorevli inherits unrelated defaults for selam() from types Selamlayan and Karsilayan.

Çoktan Seçmeli · Arayüz Metotları

Soru 12: private Arayüz Metodu

Java 9+ arayüzündeki private String baslik() { return "Belge"; } metodunu kimler çağırabilir?

C: private arayüz metotları, default ve static metotların ortak yardımcı kodunu dışarı açmadan paylaşmak içindir. Gerçekleştiren Rapor sınıfı baslik()’ı çağıramaz: cannot find symbol.

Çoktan Seçmeli · Mühürlü Tipler

Soru 13: Mühürlü Hiyerarşi

sealed abstract class Sekil permits Kare, Cember; final class Kare extends Sekil; non-sealed class Cember extends Sekil. Hangisi doğrudur? (Java 17+)

B: non-sealed kısıtı kaldırır, Cember’i herkes genişletebilir. Ucgen permits listesinde yok: class is not allowed to extend sealed class: Sekil.

Hata Bulma · Mühürlü Tipler

Soru 14: Belirleyicisi Eksik Alt Tip

Kod derlenmiyor (Java 17+). Hata hangi satırda, nedir? Üç farklı düzeltme yazın; her birinin anlamı nedir?

sealed interface Hayvan permits Kedi, Kopek { }
class Kedi implements Hayvan { }
final class Kopek implements Hayvan { }
Cevabı göster
error: sealed, non-sealed or final
  modifiers expected
class Kedi implements Hayvan { }

permits listesindeki her alt tip birini seçmek zorundadır:

  • final class Kedi: hiyerarşi burada biter.
  • sealed class Kedi permits Tekir: yeniden kısıtlar (Tekir de birini seçmelidir).
  • non-sealed class Kedi: herkes genişletebilir.

Çoktan Seçmeli · Karşılaştırma

Soru 15: Yalnızca Soyut Sınıfta

Aşağıdakilerden hangisi soyut sınıfta yapılabilir ama arayüzde yapılamaz?

D: Arayüzün nesnesi ve durumu yoktur: örnek alanı ve yapıcı tanımlanamaz. Gövdeli metot arayüzde de olur (default, static, private); sabitler ikisinde de tanımlanır; bir sınıfın birden çok tipi birlikte alması (B) ise yalnızca arayüzlerle mümkündür.

Kod Yazma · Karşılaştırma

Soru 16: Taşıt ve Şarj

Plakası ve yapıcısı olan, soyut int tekerSayisi() metodu bulunan Tasit; KAPASITE = 100 sabiti ve void sarjEt(int yuzde) metodu olan Sarj. Hangisi soyut sınıf, hangisi arayüz olmalı? İkisini birlikte kullanan, doluluğu %20’den başlayıp kapasiteyi aşmayan ElektrikliAraba’yı yazın. İki kez sarjEt(50) sonrası doluluk kaçtır?

Cevabı göster

Tasit: ortak alan + yapıcı → soyut sınıf. Sarj: ilgisiz sınıflara da verilebilecek yetenek → arayüz.

class ElektrikliAraba extends Tasit implements Sarj {
  private int doluluk = 20;
  ElektrikliAraba(String plaka) { super(plaka); }
  int tekerSayisi() { return 4; }
  public void sarjEt(int yuzde) {
    doluluk = Math.min(KAPASITE, doluluk + yuzde);
  }
  int getDoluluk() { return doluluk; }
}

20 → 70 → 100 (120 değil): 100. Önce extends, sonra implements; sarjEt public olmalı. Nesne hem Tasit hem Sarj tipindeki referansa atanabilir.

Son

Bölüm 4: Soyut Sınıflar ve Arayüzler: Çalışma Soruları
Konu anlatımı: soyut sınıflar ve arayüzler sunumu · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.