SEN1001 · 12. hafta · Classes and Objects: A Deeper Look

this, static üyeler, final sabitler ve toString

Parametre alanı gölgelediğinde this, kurucuları birbirine bağlayan this(...), bütün nesnelerin paylaştığı static alanlar, değişmeyen final değerler ve nesneyi okunur yazdıran toString. Final sınavında 'what is printed' sorularının favorisi.

this referenceshadowingconstructor chaining this(...)static field (class variable)static methodinstance variablefinalconstantstatic finaltoStringmethod overriding@OverrideString.format

Sınıf yazmayı biliyorsun. Bu hafta sınıfların içinde sık kullanılan dört araç var: this, static, final ve toString. Her biri birkaç kurala dayanıyor ama sınavda bu kurallar küçük farklarla tuzak olarak kurulur: kurucuda this unutulmuş bir sınıf, static bir sayaç, toString’i otomatik çağrılan bir println.

Altın kurallar:

  1. Parametre alanla aynı addaysa this. olmadan alana ulaşamazsın.
  2. static alan tek kopya; bütün nesneler paylaşır. Örnek alanı her nesnede ayrı.
  3. static metot örnek alanlarına doğrudan erişemez.
  4. final bir kez atanır. Sabitler static final ve BÜYÜK_HARF.
  5. println(nesne) otomatik toString() çağırır.

this referansı

Her örnek metodunun içinde gizli bir değişken var: this. Metodu çağıran nesneyi gösterir. p.getName() çağrısında this, p’dir.

Gölgeleme (shadowing)

Kurucu parametrelerine alanlarla aynı adı vermek yaygın bir alışkanlık. Ama o zaman metodun içinde o isim parametreyi gösterir:

class BadPlayer {
    private String name;
    private int number;
    public BadPlayer(String name, int number) {
        name = name;          // parametre = parametre
        number = number;
    }
    ...
}
class Player {
    private String name;
    private int number;
    public Player(String name, int number) {
        this.name = name;     // alan = parametre
        this.number = number;
    }
    ...
}
// main içinde:
BadPlayer bp = new BadPlayer("Deniz", 22);
System.out.println(bp.getName() + " " + bp.getNumber());
Player p = new Player("Deniz", 22);
System.out.println(p.getName() + " " + p.getNumber());
null 0
Deniz 22

BadPlayer derlenir ve çalışır, ama alanlar hiç atanmaz. Derleyici uyarmaz; tipik bir mantık hatası.

this(…) ile kurucu zinciri

Birden çok kurucu varsa ortak işi bir tanesinde yapıp diğerlerinden onu çağırabilirsin:

class Time {
    private int hour, minute;
    public Time() { this(0, 0); }
    public Time(int hour) { this(hour, 0); }
    public Time(int hour, int minute) {
        this.hour = hour;
        this.minute = minute;
    }
    @Override
    public String toString() {
        return String.format("%02d:%02d", hour, minute);
    }
}
// main: System.out.println(new Time() + " " + new Time(9) + " " + new Time(14, 30));
00:00 09:00 14:30

this(...) çağrısını kurucunun ilk satırına yaz. Ders kitabının ve Java 21’e kadarki sürümlerin kuralı bu; javac --release 21 öncesine bir satır yazılmış kurucuyu flexible constructors is not supported in -source 21 diyerek reddetti. (Java 25 ile bu kural gevşedi, ama sınavda klasik kuralı uygula.) Doğrulama gibi kurallar sadece bir kurucuda yazılır, tekrar edilmez.

return this

Bir metot this döndürürse çağrılar zincirlenebilir. Soru bankasındaki Temp örneği bunu gösteriyor: new Temp(20).add(5).add(3) aynı nesneye art arda ekler.

static üyeler

Örnek değişkeni (instance variable) her nesnede ayrıdır. static bir alan ise sınıfa aittir ve bellekte tek kopya vardır; bütün nesneler onu paylaşır. Bu yüzden ona sınıf değişkeni (class variable) da denir.

class Ticket {
    private static int count = 0;    // kaç bilet oluşturuldu (paylaşılan)
    private int id;                  // bu biletin numarası (her nesnede ayrı)
    private String owner;
    public Ticket(String owner) {
        this.owner = owner;
        count++;
        id = count;
    }
    public static int getCount() { return count; }
    public int getId() { return id; }
    public int getCountViaInstance() { return count; }
}
// main içinde:
System.out.println(Ticket.getCount());
Ticket a = new Ticket("A");
Ticket b = new Ticket("B");
Ticket c = new Ticket("C");
System.out.println(Ticket.getCount() + " " + a.getId() + " " + b.getId() + " " + c.getId());
System.out.println(a.getCountViaInstance());
0
3 1 2 3
3
Ticket sınıfı:  count = 3     (tek kopya)
a: id = 1    b: id = 2    c: id = 3     (her nesnede ayrı)
  • Hiç nesne yokken bile Ticket.getCount() çalıştı: static üyeler nesneye ihtiyaç duymaz, sınıf adıyla kullanılır.
  • Örnek metodu (getCountViaInstance) static alanı okuyabilir.
  • Ters yön çalışmaz: static bir metot this’e sahip değildir, hangi nesnenin alanını kastettiğini bilemez.
public class Main {
    private int score = 5;
    public static void main(String[] args) {
        System.out.println(score);
    }
}
Main.java:5: error: non-static variable score cannot be referenced from a static context

Bu hatayı ilk haftalardan beri main’e yardımcı metot yazarken görmüş olabilirsin: main static olduğu için çağırdığı metotlar da static olmalıydı.

Soru bankasındaki Counter örneğini iz tablosuyla çöz: static alan için sınıfın yanına tek bir kutu, örnek alanı için her nesnenin yanına ayrı bir kutu çiz.

çağrı      x.mine   y.mine   Counter.total
başlangıç  0        0        0
x.hit()    1        0        1
y.hit()    1        1        2
y.hit()    1        2        3

Her hit iki kutuyu birden artırıyor: çağıran nesnenin kendi kutusunu ve herkesin paylaştığı tek kutuyu.

Ne zaman static? Kendine şunu sor: “Bu bilgi tek bir nesneye mi ait, yoksa bütün sınıfa mı?” Bir öğrencinin notu o öğrenciye aittir: örnek alanı. Toplam öğrenci sayısı, KDV oranı ya da bir sonraki verilecek numara bütün sınıfa aittir: static. Metotlar için de aynı soru: metot bir nesnenin alanlarını kullanıyorsa örnek metodu, sadece parametreleriyle çalışıyorsa (Math.max gibi) static olabilir.

staticstatic değil
Kime aitsınıfaher nesneye
Kaç kopya1nesne sayısı kadar
ErişimTicket.getCount()a.getId()
Örneksayaç, sabitler, Math.sqrtad, bakiye, not

final ve sabitler

final bir değişkene bir kez değer atanabileceğini söyler.

class Shop {
    public static final double TAX_RATE = 0.20;          // sabit (constant)
    public static double priceWithTax(double price) {
        return price * (1 + TAX_RATE);
    }
}
class Circle {
    private final double radius;                         // kurucuda bir kez atanır
    public Circle(double radius) { this.radius = radius; }
    public double area() { return Math.PI * radius * radius; }
}
// main: Shop.priceWithTax(100), Shop.TAX_RATE, new Circle(2).area() (%.2f)
120.0
0.2
12.57
  • Sabit (constant) için static final birlikte kullanılır: tek kopya ve değişmez. Adı büyük harf ve alt çizgiyle yazılır: TAX_RATE, MAX_SIZE. Math.PI de böyle bir sabit.
  • final örnek alanı her nesnede farklı olabilir ama nesne oluştuktan sonra değişmez. Kurucuda atanır.

Atamaya çalışırsan derlenmez:

Main.java:6: error: cannot assign a value to static final variable MAX
Main2.java:4: error: cannot assign a value to final variable radius

toString

Her sınıf, Java’nın kök sınıfı Object’ten bir toString() metodu alır. Varsayılan sürüm işe yaramaz bir metin döndürür: sınıf adı, @ ve bir hash kodu (NoToString@1b6d3586 gibi). Kendi sürümünü yazarsan (override):

@Override
public String toString() {
    return name + " #" + number;
}
// main içinde:
Player p2 = new Player("Can", 7);
System.out.println(p2);                 // println otomatik toString çağırır
String msg = "Kaptan: " + p2;           // birleştirme de çağırır
System.out.println(msg);
Can #7
Kaptan: Can #7

Kurallar:

  • İmza tam olarak public String toString(). Parametre yok, dönüş tipi String, public.
  • Metot yazdırmaz, döndürür. İçine println koymak yanlış bir alışkanlık.
  • @Override etiketi zorunlu değil ama iyi: imzayı yanlış yazarsan derleyici uyarır.
  • String.format printf ile aynı belirteçleri kullanır ama ekrana basmak yerine String döndürür; toString içinde çok işe yarar.

Sık yapılan hatalar

Yanlış düşünceDoğrusu
name = name; alanı atarParametreyi kendine atar; this.name = name;
this(...) kurucunun herhangi bir yerindeİlk satıra yaz (Java 21 ve öncesinde zorunlu)
static metotta this kullanılabilirstatic’te this yok
static alan her nesnede ayrıTek kopya, paylaşılır
static metot için nesne şartSinif.metot() yeter
main’den örnek alanına doğrudan erişilirNesne üzerinden: obj.alan
final alan hiç atanamazBir kez atanır (tanımda ya da kurucuda)
Sabit adı camelCaseBÜYÜK_HARF: TAX_RATE
toString içinde printlnreturn ile String döndür
println(obj) alanları basartoString yazılmadıysa SinifAdi@...

Kendini test et

Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.

Soru 1orta

What is printed?

class Box {
    private int size;
    public Box(int size) { size = size * 2; }
    public int getSize() { return size; }
}
// in main:
Box b = new Box(5);
System.out.println(b.getSize());
Cevabı göster
0

Kurucunun içinde size adı parametreyi gösterir (gölgeleme, shadowing). size = size * 2 sadece parametreyi 10 yapar; alan hiç değişmez, varsayılan 0'da kalır. Doğrusu this.size = size * 2;.

Soru 2kolay

Same class, but the constructor body is this.size = size * 2;. What is printed for new Box2(5).getSize()?

Cevabı göster
10

this.size nesnenin alanı, sağdaki size parametre. Alan 5 * 2 = 10 olur.

Soru 3orta

What is printed?

class Counter {
    static int total = 0;
    private int mine = 0;
    public void hit() { mine++; total++; }
    public int getMine() { return mine; }
}
// in main:
Counter x = new Counter();
Counter y = new Counter();
x.hit();
y.hit();
y.hit();
System.out.println(x.getMine() + " " + y.getMine() + " " + Counter.total);
Cevabı göster
1 2 3

mine örnek değişkeni: her nesnede ayrı (x'te 1, y'de 2). total static: sınıfa ait, tek bir kopya var ve bütün nesneler onu paylaşıyor. Üç hit, total 3.

Soru 4orta

Time has Time(int hour) which calls this(hour, 0), and toString returns String.format("%02d:%02d", hour, minute). What is printed?

Time t = new Time(7);
System.out.println(t);
Cevabı göster
07:00

this(hour, 0) aynı sınıftaki iki parametreli kurucuyu çağırır: hour = 7, minute = 0. println bir nesne alınca otomatik toString() çağırır. %02d sayıyı iki haneye sıfırla tamamlar: 07.

Soru 5kolay

Player.toString() returns name + " #" + number. What is printed?

Player p = new Player("Ali", 10);
System.out.println("#" + p + "#");
Cevabı göster
#Ali #10#

String birleştirmede nesne kullanılınca Java onun toString() metodunu çağırır: "Ali #10". Başına ve sonuna # eklenir.

Soru 6zor

Ticket has private static int count; each constructor call does count++; id = count;. Assume count starts at 0. What is printed?

Ticket t = new Ticket("X");
Ticket u = new Ticket("Y");
System.out.println(t.getId() + u.getId() + Ticket.getCount());
Cevabı göster
5

t'nin id'si 1, u'nunki 2, count 2. Üçü de int ve başta String yok: toplama yapılır, 1 + 2 + 2 = 5. Birleştirme isteseydin başa "" + koyardın: "122".

Soru 7kolay

Shop has public static final double TAX_RATE = 0.20; and priceWithTax(p) returns p * (1 + TAX_RATE). What is printed?

System.out.println(Shop.priceWithTax(50) + " " + (int) Shop.priceWithTax(10));
Cevabı göster
60.0 12

Static metot sınıf adıyla çağrılır, nesne gerekmez. 50 * 1.2 = 60.0 (double). 10 * 1.2 = 12.0, cast ile 12.

Soru 8zor

What is printed?

class Temp {
    private int value;
    public Temp(int value) { this.value = value; }
    public Temp add(int d) { value += d; return this; }
    public String toString() { return value + "C"; }
}
// in main:
Temp tm = new Temp(20).add(5).add(3);
System.out.println(tm);
Cevabı göster
28C

return this metodu çağıran nesnenin kendisini döndürür, bu yüzden çağrılar zincirlenebilir (method chaining). Aynı nesneye önce 5, sonra 3 eklenir: 28.

Soru 9orta

Which lines do not compile?

public class Main {
    private int score = 5;
    public static final int MAX = 10;
    public static void main(String[] args) {
        System.out.println(score);   // line A
        System.out.println(MAX);     // line B
        MAX = 20;                    // line C
    }
}
Cevabı göster
line A and line C

A: main static; hangi nesnenin score'u olduğu belli değil → non-static variable score cannot be referenced from a static context. B: static alan static metottan okunabilir. C: final değişkene ikinci kez değer atanamaz → cannot assign a value to static final variable MAX.

Soru 10kolay

A class has no toString method. What does System.out.println(obj) print?

  1. Nothing
  2. The values of all fields
  3. Class name, @ and a hexadecimal hash code (e.g. NoToString@1b6d3586)
  4. A compile-time error
Cevabı göster
c

Her sınıf Object'ten varsayılan bir toString alır: SınıfAdı@hashKodu. Kod her çalıştırmada değişebilir. Alanları görmek istiyorsan toString'i kendin yazmalısın (override).

Soru 11kolay

Write a constructor for Player (fields private String name; private int number;) whose parameters have the same names as the fields.

Cevabı göster
public Player(String name, int number) { this.name = name; this.number = number; }

Parametre adları alanları gölgeler; alana ulaşmak için this. şart.public Player(String name, int number) { this.name = name; this.number = number;}this olmadan (name = name;) yazılan sürüm doğrulamada null 0 bastı.

Soru 12orta

Write a toString method for Player that returns the name, a space, # and the number (e.g. Can #7).

Cevabı göster
public String toString() { return name + " #" + number; }

İmza tam olarak public String toString() olmalı: public, dönüş tipi String, parametre yok. Metot yazdırmaz, döndürür.@Overridepublic String toString() { return name + " #" + number;}System.out.println(new Player("Can", 7)); → Can #7.

Doğrulama: Tüm çıktılar JDK 26 ile çalıştırıldı (verify/SEN1001/W12.java; Player, BadPlayer, Time, Ticket, Shop, Circle, Box, Box2, Counter ve Temp sınıfları aynı dosyada). static ve final derleme hataları verify/SEN1001/err/st/ altında javac ile alındı; this(...) kuralı javac --release 21 ile ayrıca denendi.

Deftere not kartı

this = metodu çağıran nesnenin kendisi Parametre alanla aynı adda → this.ad = ad; (ad = ad; hiçbir şey yapmaz!) this(...) aynı sınıftaki başka kurucuyu çağırır, kurucunun İLK satırına yaz return this; → zincirleme çağrı: new Temp(20).add(5).add(3) static alan: sınıfa ait, TEK kopya, bütün nesneler paylaşır (sayaç, id üretme) örnek alanı: her nesnede ayrı kopya static metot: Sinif.metot() örnek alanına/metoduna doğrudan erişemez (static context hatası) örnek metodu static alanı okuyup değiştirebilir final: bir kez atanır, sonra değişmez sabit: public static final double TAX_RATE = 0.20; Sabit adı BÜYÜK_HARF final alan kurucuda atanabilir toString: public String toString() { return ...; } println(obj) ve "x" + obj otomatik çağırır toString yoksa → SinifAdi@1b6d3586 String.format("%02d:%02d", h, m) → printf gibi ama String döndürür