Bölüm 4.1: Nesneler ve Sınıflar

Java ile Nesne Yönelimli Programlama
Sınıf ve nesneYapıcı metotlarAlan ve metot türleristatic üyeler Erişim ve veri gizlemeReferanslar ve this== ve equalsWrapper sınıflar record ve enumİç sınıflarSınıf türleri
Sercan KÜLCÜ · Giresun Üniversitesi · Elektrik-Elektronik Mühendisliği

Giriş

Öğrenme Çıktıları

Sınıf ve nesne

Sınıfı bir taslak, nesneyi o taslaktan üretilmiş somut bir örnek olarak açıklamak; alan ve metotlarıyla bir sınıf yazmak.

Nesne oluşturmak

new işlecini ve yapıcı metotları (constructor) kullanmak; varsayılan değerleri ve varsayılan yapıcıyı bilmek.

Örnek ve sınıf üyeleri

Örneğe ait ve static alan/metotları ayırt etmek; ilklendirici bloklarının çalışma sırasını izlemek.

Referanslar

Değişkenin nesneyi değil referansı tuttuğunu bellek çizimiyle göstermek; this, == ve equals farkını açıklamak.

Yapıcı zinciri ve erişim

this(...) ile yapıcıları zincirlemek; erişim belirleyicilerin ve veri gizlemenin amacını açıklamak.

Özel sınıf türleri

Wrapper sınıfları, record, enum ve iç sınıfları tanımak; RasyonelSayi örneğiyle bir sınıfı baştan tasarlamak.

Nesne Yönelimli Programlama

Nesne Yönelimli Programlama

  • Nesne yönelimli programlama (Object-Oriented Programming, OOP), programı birbiriyle etkileşen nesneler olarak kuran bir yaklaşımdır.
  • Nesne (object), gerçek dünyada açıkça tanımlanabilen bir varlığı temsil eder: bir öğrenci, bir masa, bir çember, ekrandaki bir düğme, hatta bir kredi.
  • Her nesnenin durumu (verileri) ve davranışı (yapabildikleri) vardır.
Benzetme: bir okul, öğrenci, öğretmen ve ders nesnelerinin birbirine mesaj göndermesiyle (metot çağırmasıyla) işler.
NesneAlanlar (durum)Davranışlar
Öğrenciad, numara, bölümderseKaydol(), notGor()
Masaen, boy, malzemetasi()
Çembermerkez, yarıçapalan(), cevre()
Düğmeyazı, renk, etkin mitikla()
Kreditutar, faiz, vadetaksitHesapla()

Nesne Yönelimli Programlama

Nesneler: Alan ve Davranış

  • Bir sınıfın üyeleri (members) vardır: alanlar (fields), metotlar (methods) ve yapıcılar (constructors).
  • Nesneler veri saklar: bu veri parçalarına alan (field) denir.
  • Nesneler işlem yapar: bu işlemlere davranış (metot, method) denir.
  • Veriyi ve o veri üzerinde çalışan kodu bir araya getirmek, programı daha düzenli, yeniden kullanılabilir ve sezgisel yapar.
ogrenci1 : Ogrenciad = "Ali"numara = 2012bolum = "EEM"selamVer()dersEkle(ad, not)ortalama()← alanlar (fields)← davranışlar (methods)

Nesne Yönelimli Programlama

Prosedürel ve Nesne Yönelimli

Prosedürel (yordamsal) yaklaşımNesne yönelimli yaklaşım
Temel birimFonksiyon (metot)Nesne (veri + metotlar)
VeriAyrı değişkenlerde; her fonksiyon erişebilirNesnenin içinde; dışarıya kontrollü açılır
ÖrnekalanHesapla(en, boy)dikdortgen.alanHesapla()
Büyük programlarDeğişiklik birçok fonksiyonu etkilerDeğişiklik çoğunlukla bir sınıfın içinde kalır
Yeniden kullanımFonksiyonları kopyalayarakSınıfları kullanarak ve kalıtımla

Şimdiye kadar yazdığımız static metotlu programlar prosedürel tarzdaydı. Java'da her kod bir sınıfın içindedir; nesne yönelimli programlamada sınıflar nesne üretmek için kullanılır.

ProsedürelalanHesapla()cevreHesapla()ciz()en, boy (veri)Nesne yönelimlidikdortgenen=5, boy=3alanHesapla() …kareen=4, boy=4alanHesapla() …

Nesne Yönelimli Programlama

Üç Temel Özellik

Sarmalama (Encapsulation)

Nesne, alan ve davranışlarının ayrıntısını diğer nesnelerden gizleyebilir. Dışarıya karşı kapalı bir kutu gibidir; yalnızca izin verilen metotlarla kullanılır.

Kalıtım (Inheritance)

Bir sınıf, başka bir sınıfın alan ve metotlarını kalıtımla alabilir. Kodun yeniden kullanımını ve sınıf hiyerarşisini sağlar.

Çok Biçimlilik (Polymorphism)

Bir nesne birden fazla biçim (tip) alabilir; aynı çağrı farklı nesnelerde farklı davranır. Esneklik ve dinamik davranış sağlar.

Bunlara çoğu zaman dördüncü olarak soyutlama (abstraction) eklenir: gereksiz ayrıntıyı gizleyip yalnızca önemli özellikleri göstermek.

Sınıf ve Nesne

Sınıf: Nesnenin Taslağı

  • Sınıf (class), bir nesnenin taslağıdır (blueprint); bir sınıftan farklı verileri taşıyan birçok nesne üretilebilir.
  • Sınıf, nesnenin taşıyacağı verileri (alanlar) ve yapabileceği işlemleri (metotlar) belirtir.
  • Bir nesne, bir sınıfın örneğidir (instance): sınıfın bellekteki somut hâlidir.
  • Sınıflar, gerçek dünyadaki varlıkları modellemeyi sağlar: bir Araba sınıfı her otomobili temsil edebilir; her marka ve model bu sınıftan üretilen bir nesnedir.
Sınıf (taslak)Arabamarkamodelyilrenkilerle()dur()sinyalVer()newaraba1 : ArabaToyota Corollaaraba2 : ArabaFord Mustangaraba3 : ArabaFiat EgeaNesneler (örnekler)

Benzetme: sınıf kurabiye kalıbı, nesneler o kalıpla kesilen kurabiyelerdir.

Sınıf ve Nesne

Örnek: Araba Sınıfı

Alanlar (veriler)

Marka, Model, Yıl, Renk

Metotlar (işlemler)

Hareket et (ilerle), Dur, Sinyal ver

Aynı sınıftan üretilen iki nesne aynı alan adlarına ama farklı değerlere sahiptir.

Araba- marka : String- model : String- yil : int- renk : String+ ilerle() : void+ dur() : void+ sinyalVer() : voidaraba1 : Arabamarka = "Toyota"model = "Corolla"yil = 2022renk = "Gri"araba2 : Arabamarka = "Ford"model = "Mustang"yil = 2023renk = "Mavi"örneği

UML sınıf diyagramı: ad / alanlar / metotlar; - private, + public. Nesne adları altı çizili yazılır.

Sınıf ve Nesne

Sınıf Tanımlama

public class Araba {
  // Alanlar (fields)
  String marka;
  String model;
  int yil;
  String renk;

  // Metotlar (methods)
  void ilerle() {
    System.out.println(marka + " ilerliyor.");
  }

  void dur() {
    System.out.println(marka + " durdu.");
  }

  void sinyalVer() {
    System.out.println(marka + " sinyal veriyor.");
  }
}
  • class anahtar sözcüğü ve sınıf adıyla başlar; gövde { } arasındadır.
  • Sınıf adı büyük harfle başlar (Araba, BankaHesabi); public bir sınıf, aynı adlı dosyada (Araba.java) bulunmalıdır.
  • Alanlar sınıf gövdesinde, metotların dışında tanımlanır; her metot bu alanları doğrudan kullanabilir.
  • Metotların önünde static yok: her biri belirli bir arabanın (nesnenin) metodudur.
  • Bu sınıfta main yok; tek başına çalışmaz, başka bir sınıf onu kullanır.

Sınıf ve Nesne

Sınıfın Kullanımı

public class AracTesti {
  public static void main(String[] args) {
    Araba araba1 = new Araba();
    araba1.marka = "Toyota";
    araba1.model = "Corolla";
    araba1.yil = 2022;
    araba1.renk = "Gri";

    Araba araba2 = new Araba();
    araba2.marka = "Ford";
    araba2.model = "Mustang";
    araba2.yil = 2023;
    araba2.renk = "Mavi";

    araba1.ilerle();
    araba2.sinyalVer();
    araba1.dur();
  }
}
Çıktı
Toyota ilerliyor.
Ford sinyal veriyor.
Toyota durdu.
  • new Araba() bir nesne üretir; araba1 onu gösterir.
  • araba1.marka = "Toyota";: nokta (.) ile nesnenin alanına erişilir.
  • araba1.ilerle(): metot, araba1'in verileriyle çalışır; araba2.sinyalVer() ise araba2'ninkilerle.
  • Alanları dışarıdan böyle doğrudan değiştirmek iyi bir alışkanlık değildir; doğrusu yapıcı ve erişim metotları kullanmaktır.

Sınıf ve Nesne

Sınıfın Üyeleri

Alanlar (fields)

Nesnelerin taşıyabileceği verileri temsil eder. Örnek: bir Ogrenci sınıfında ad ve soyad.

Metotlar (methods)

Nesnelerin yapabileceği işlemleri tanımlar. Örnek: bir Kopek sınıfında havla() ve kos().

Erişim düzeyi

Her üye private, protected, varsayılan (yazılmaz) veya public olabilir: kimin kullanabileceğini belirler.

Sahiplik

Her üye nesneye ait (instance, varsayılan) veya static ile sınıfa ait olabilir.

Yapıcı metotlar da sınıfın içinde yazılır; ama yalnızca nesne oluşturulurken çalışırlar ve teknik olarak metot değil, ayrı bir üye türüdür. Sınıfın içinde başka sınıflar (iç sınıflar) da tanımlanabilir.

Sınıf ve Nesne

Erişim Belirleyiciler ve Veri Gizleme

  • Erişim belirleyiciler (public, protected, private, yazılmazsa paket erişimi), bir üyeye sınıfın dışından kimin erişebileceğini belirtir.
  • Genel kural: alanlar private, dışarıya sunulan metotlar public.
  • Alanın değeri bir erişimci (getter, get...) ile okunur, bir değiştirici (setter, set...) ile değiştirilir; değiştirici geçersiz değeri reddeder.
  • Bu düzen veri gizlemedir (data hiding): alanlara yalnızca kendi sınıfının metotları doğrudan erişir. Sarmalamanın (encapsulation) temelidir.
public class BankaHesabi {
  private double hesapBakiyesi;   // gizli alan
  public double getHesapBakiyesi() {
    return hesapBakiyesi;
  }
  public void setHesapBakiyesi(double b) {
    if (b >= 0) hesapBakiyesi = b;  // geçersizi reddet
  }
}
// başka bir sınıfta:
hesap.hesapBakiyesi = -500;
error: hesapBakiyesi has private access in BankaHesabi

Yapıcı Metotlar

Yapıcı Metotlar

  • Yapıcı metot (constructor), nesne oluşturmak için kullanılan özel bir metottur; new ile nesne oluşturulduğunda otomatik çağrılır.
  • Görevi, alanlara ilk değerlerini vermek ve varsa başka hazırlık işlerini yapmaktır.
  • Adı sınıf adıyla aynıdır (büyük-küçük harf dahil).
  • Dönüş tipi yoktur, void bile yazılmaz; değer döndüremez.
  • Genellikle public tanımlanır; nesne oluşturmayı kısıtlamak için private da olabilir (ör. singleton deseni).
  • Bir sınıfın birden çok yapıcısı olabilir (farklı parametrelerle).
public class Ogrenci {
  private String ad;
  private int numara;

  // Yapıcı: sınıfla aynı ad, dönüş türü yok
  public Ogrenci(String ad, int numara) {
    this.ad = ad;
    this.numara = numara;
  }
}

// Kullanımı:
Ogrenci ogr = new Ogrenci("Ali", 2012);

Yapıcı Metotlar

Nesne Nasıl Oluşturulur?

SinifAdi nesneAdi = new SinifAdi(parametreler);

Araba corolla = new Araba("Toyota", "Corolla", 2022);
Scanner klavye = new Scanner(System.in);
Kitap kitap = new Kitap();
import java.util.Scanner;
public class Olusturma {
  public static void main(String[] args) {
    Scanner klavye = new Scanner(System.in);
    StringBuilder metin = new StringBuilder("Java");
    String baslik = "Nesneler";           // kısayol
    String yazar = new String("Sercan");  // uzun yol
    metin.append(" 21");
    System.out.println(metin + " / " + baslik);
    System.out.println(yazar.length());
    System.out.println(klavye.nextInt() * 2);
  }
}

Kısayol: String baslik = "Nesneler"; String nesnesi oluşturur; yalnızca String baslik; ise sadece referans tanımlar.

  1. new, heap'te nesne için yer ayırır; alanlar varsayılan değerleri alır.
  2. Yapıcı metot çağrılır, ilk değerleri verir.
  3. new ifadesinin sonucu nesnenin referansıdır; değişkene atanır.
Çıktı
(girdi: 21)
Java 21 / Nesneler
6
42

Yapıcı Metotlar

Yapıcı Örneği: Araba

public class Araba {
  private String model;
  private String renk;

  public Araba(String model, String renk) {
    this.model = model;
    this.renk = renk;
  }

  public void bilgiYazdir() {
    System.out.println(model + " - " + renk);
  }

}
public static void main(String[] args) {
  Araba sporAraba = new Araba("2022", "KIRMIZI");
  Araba klasikAraba = new Araba("2023", "BEYAZ");
  sporAraba.bilgiYazdir();
  klasikAraba.bilgiYazdir();
}
Yığın (stack)Heapmain()sporArabaklasikArabaAraba nesnesimodel"2022"renk"KIRMIZI"Araba nesnesimodel"2023"renk"BEYAZ"
Çıktı
2022 - KIRMIZI
2023 - BEYAZ

Yapıcı Metotlar

Referanslar

  • Bir nesne doğrudan kullanılamaz; ona yalnızca referans (reference, başvuru) ile erişilir. Değişkenlerde nesnenin kendisi değil, referansı saklanır.
  • Referans, nesnenin bellekte nerede olduğunu gösteren bir adres gibi düşünülebilir.
  • int, double, boolean gibi ilkel tipli değişkenler değeri kendileri tutar; sınıf tipinden değişkenler (Araba, String, Scanner) referans tutar.
  • Hiçbir nesneyi göstermeyen referansın değeri null'dır.
Benzetme: değişken bir televizyon kumandası, nesne televizyondur. Kumandayı kopyalamak ikinci bir televizyon yaratmaz.
Yığın (stack)Heapmain()sporArabaklasikArabayeniArabanullAraba nesnesimodel"2022"renk"KIRMIZI"Araba nesnesimodel"2023"renk"BEYAZ"

Yerel değişkenler yığında (stack), nesneler heap'te bulunur; ok = referans.

Yapıcı Metotlar · Adım adım kod izleme

new Araba(...): Adım Adım

Yığın (stack)Heapmain()sporAraba?klasikAraba?Araba #1modelnullrenknull

new heap'te yeni bir nesne ayırır; String alanlar önce varsayılan değer null alır.

Yığın (stack)HeapAraba(...)thismodel"2022"renk"KIRMIZI"main()sporAraba?klasikAraba?Araba #1modelnullrenknull

Yapıcı çağrılır: parametreler argümanların kopyasını alır, this yeni nesneyi gösterir.

Yığın (stack)HeapAraba(...)thismodel"2022"renk"KIRMIZI"main()sporAraba?klasikAraba?Araba #1model"2022"renknull

this.model = model: soldaki nesnenin alanı, sağdaki parametredir.

Yığın (stack)HeapAraba(...)thismodel"2022"renk"KIRMIZI"main()sporAraba?klasikAraba?Araba #1model"2022"renk"KIRMIZI"

this.renk = renk: nesne artık hazır.

Yığın (stack)Heapmain()sporArabaklasikAraba?Araba #1model"2022"renk"KIRMIZI"

Yapıcı biter, çerçevesi silinir. new ifadesinin değeri olan referans sporAraba'ya atanır.

Yığın (stack)Heapmain()sporArabaklasikArabaAraba #1model"2022"renk"KIRMIZI"Araba #2model"2023"renk"BEYAZ"

Aynı adımlar ikinci kez: ayrı bir nesne oluşur, kendi model ve renk kopyalarıyla.

Yığın (stack)HeapbilgiYazdir()thismain()sporArabaklasikArabaAraba #1model"2022"renk"KIRMIZI"Araba #2model"2023"renk"BEYAZ"

sporAraba.bilgiYazdir(): metotta this = #1, bu yüzden #1'in alanları yazılır.

Yığın (stack)HeapbilgiYazdir()thismain()sporArabaklasikArabaAraba #1model"2022"renk"KIRMIZI"Araba #2model"2023"renk"BEYAZ"

Aynı metot, bu kez this = #2. Kod tek, veriler nesne başına ayrıdır.

public class Araba {
  private String model;
  private String renk;

  public Araba(String model, String renk) {
    this.model = model;
    this.renk = renk;
  }

  public void bilgiYazdir() {
    System.out.println(model + " - " + renk);
  }

  public static void main(String[] args) {
    Araba sporAraba = new Araba("2022", "KIRMIZI");
    Araba klasikAraba = new Araba("2023", "BEYAZ");
    sporAraba.bilgiYazdir();
    klasikAraba.bilgiYazdir();
  }
}

Yapıcı Metotlar

Varsayılan Yapıcı Metot

  • Sınıfa hiç yapıcı yazılmamışsa derleyici varsayılan yapıcıyı (default constructor) ekler: parametresiz, gövdesi boş. Nesne oluşturulurken her zaman bir yapıcı çağrılır.
  • Değer verilmeyen alanlar varsayılan değer alır (yerel değişkenler almaz):
Alan tipiVarsayılan değer
byte short int long0
float double0.0
booleanfalse
char'\u0000' (kod 0)
Referans (String, diziler, nesneler)null
class Nokta3 {
  int x;
  double agirlik;
  boolean gorunur;
  char harf;
  String ad;
}
public class Varsayilan {
  public static void main(String[] args) {
    Nokta3 n = new Nokta3();   // varsayılan yapıcı
    System.out.println(n.x + " " + n.agirlik);
    System.out.println(n.gorunur + " " + n.ad);
    System.out.println((int) n.harf);
  }
}
Çıktı
0 0.0
false null
0

Yapıcı Metotlar

Parametresiz ve Parametreli Yapıcı

public class Arac {
  private String marka;
  private String model;
  private int yil;
  public Arac() {                 // parametresiz yapıcı
    marka = "Bilinmiyor";
    model = "Bilinmiyor";
    yil = 0;
  }
  public Arac(String marka, String model, int yil) {
    this.marka = marka;
    this.model = model;
    this.yil = yil;
  }
  public void bilgiYazdir() {
    System.out.println(marka + " " + model + " " + yil);
  }
  public static void main(String[] args) {
    Arac a1 = new Arac();
    Arac a2 = new Arac("Renault", "Clio", 2021);
    a1.bilgiYazdir();
    a2.bilgiYazdir();
  }
}
Çıktı
Bilinmiyor Bilinmiyor 0
Renault Clio 2021
  • Arac(), kendi yazdığımız parametresiz yapıcıdır; alanları anlamlı başlangıç değerlerine ayarlar.
  • İki yapıcı aynı adı taşır, parametreleri farklıdır: yapıcı aşırı yükleme. Hangisinin çalışacağını argümanlar belirler.
  • Sınıfa herhangi bir yapıcı yazıldığında derleyici artık varsayılan yapıcı eklemez. Yalnızca parametreli yapıcı varsa new Arac() derlenmez: constructor Arac in class Arac cannot be applied to given types.

Alanlar

Alanlar ve Türleri

Alanlar, sınıfın içinde (metotların dışında) tanımlanan veri değişkenleridir. İki temel türü vardır:

Örneğe ait alan (instance field)Sınıfa ait alan (static field)
Tanımprivate String ad;private static int toplamHesapSayisi;
Kopya sayısıHer nesnede ayrı bir kopyaSınıfta tek kopya, tüm nesneler paylaşır
Ne zaman oluşur?Her new ileSınıf belleğe yüklenirken, bir kez
Erişimnesne.adSinifAdi.toplamHesapSayisi
ÖrnekOgrenci: ad, soyadBankaHesabi: toplamHesapSayisi
  • Sabit (final) alanlara değer bir kez verilir, sonra değiştirilemez. Sınıf sabitleri genellikle static final ve BÜYÜK_HARF yazılır: Math.PI.
  • Sınıfa ait ilklendiriciler (static { }) sınıf yüklenirken bir kez; örneğe ait ilklendiriciler ({ }) her nesne oluşturulduğunda çalışır.

Alanlar · Adım adım kod izleme

static Sayaç: Adım Adım

Yığın (stack)HeapSınıf alanı (static): BankaHesabitoplamHesapSayisi0

Sınıf belleğe yüklenirken static alan bir kez oluşur ve 0 olur. Henüz hiç nesne yok.

Yığın (stack)HeapSınıf alanı (static): BankaHesabitoplamHesapSayisi1yapıcı metotthismain()h1?h2?h3?BankaHesabi #1hesapSahibi"Ali"

İlk nesne: kendi hesapSahibi kopyası "Ali" olur; ortak sayaç 1'e çıkar.

Yığın (stack)HeapSınıf alanı (static): BankaHesabitoplamHesapSayisi1main()h1h2?h3?BankaHesabi #1hesapSahibi"Ali"

h1 birinci nesneyi gösterir.

Yığın (stack)HeapSınıf alanı (static): BankaHesabitoplamHesapSayisi2main()h1h2h3?BankaHesabi #1hesapSahibi"Ali"BankaHesabi #2hesapSahibi"Ayşe"

İkinci nesnenin ayrı bir hesapSahibi alanı var; sayaç ise aynı alan: 2.

Yığın (stack)HeapSınıf alanı (static): BankaHesabitoplamHesapSayisi3main()h1h2h3BankaHesabi #1hesapSahibi"Ali"BankaHesabi #2hesapSahibi"Ayşe"BankaHesabi #3hesapSahibi"Can"

Üç nesne, üç hesapSahibi; ama tek toplamHesapSayisi = 3.

Yığın (stack)HeapSınıf alanı (static): BankaHesabitoplamHesapSayisi3main()h1h2h3BankaHesabi #1hesapSahibi"Ali"BankaHesabi #2hesapSahibi"Ayşe"BankaHesabi #3hesapSahibi"Can"

h2.hesapSahibi: örnek alanı nesne üzerinden okunur.

Yığın (stack)HeapSınıf alanı (static): BankaHesabitoplamHesapSayisi3static metotmain()h1h2h3BankaHesabi #1hesapSahibi"Ali"BankaHesabi #2hesapSahibi"Ayşe"BankaHesabi #3hesapSahibi"Can"

static metot sınıf adıyla çağrılır; this'i yoktur, yalnızca static alanı okur.

Yığın (stack)HeapSınıf alanı (static): BankaHesabitoplamHesapSayisi3main()h1h2h3sayi3BankaHesabi #1hesapSahibi"Ali"BankaHesabi #2hesapSahibi"Ayşe"BankaHesabi #3hesapSahibi"Can"

Dönen 3, sayi'ya atanır ve yazdırılır.

public class BankaHesabi {
  private String hesapSahibi;
  private static int toplamHesapSayisi = 0;

  public BankaHesabi(String hesapSahibi) {
    this.hesapSahibi = hesapSahibi;
    toplamHesapSayisi++;
  }

  public static int getToplamHesapSayisi() {
    return toplamHesapSayisi;
  }

  public static void main(String[] args) {
    BankaHesabi h1 = new BankaHesabi("Ali");
    BankaHesabi h2 = new BankaHesabi("Ayşe");
    BankaHesabi h3 = new BankaHesabi("Can");
    System.out.println(h2.hesapSahibi);
    int sayi = BankaHesabi.getToplamHesapSayisi();
    System.out.println(sayi);
  }
}

Alanlar

Alan Tanımlamaları

public class Kitap {
  // Örneğe ait alanlar
  private String baslik;
  private String yazar;
  private int sayfaSayisi;
  // Sınıfa ait alan
  private static int toplamKitapSayisi;
  // final tanımlanmış bir alan (sabit)
  public static final double PI = 3.14159265359;
}
public class Alanlar {
  public int a;                         // genel
  int b = 1, c = 2;                     // varsayılan (paket)
  private double x;                     // özel
  private static int xx;                // statik, özel
  public static int y;                  // statik, genel
  public final int CONST1 = 5;          // değiştirilemez
  private static final int CONST2 = 6;  // statik sabit
}
  • Söz dizimi: [erişim] [static] [final] tür ad [= ilkDeğer];
  • Aynı satırda birden çok alan: int b = 1, c = 2;
  • PI burada örnek olarak tanımlandı; Java'da hazır bir sabit vardır: Math.PI.
  • final alana yeniden değer atamak derleme hatasıdır:
    error: cannot assign a value to final variable CONST1

Alanlar

İlklendirici Blokları

Sınıfa ait ilklendirici (static initializer)

static { ... } bloğu, sınıf belleğe ilk kez yüklenirken, yalnızca bir kez çalışır. Static alanlara karmaşık ilk değer vermek için kullanılır.

Örneğe ait ilklendirici (instance initializer)

{ ... } bloğu, her nesne oluşturulduğunda, yapıcının gövdesinden önce çalışır. Tüm yapıcılarda ortak olan işleri yapar.

Bir nesne oluşturulurken sıra: (1) sınıf ilk kez kullanılıyorsa static alanlar ve static bloklar → (2) new ile bellek ayrılır, alanlar varsayılan değer alır → (3) alan ilk değerleri ve örnek ilklendirici blokları (yazılış sırasıyla) → (4) yapıcının gövdesi.

Kopek sınıfında her ikisi de var. Not: havla()'nın döndürdüğü değer yazdırılmıyor; System.out.println(d2.havla()); yazılsaydı son satır "Gece haw haw haw!" olurdu.

1 static { } ve static alanlarsınıf ilk kullanılınca, bir kez2 new: bellek ayrılıralanlar varsayılan değerde3 alan ilk değerleri, { }yazılış sırasıyla, her new4 yapıcının gövdesiher new

Alanlar · Adım adım kod izleme

Kopek: İlklendirici Sırası

Yığın (stack)HeapKopek sınıfı yüklendistatic blok"çalıştı"

main çalışmadan önce sınıf yüklenir: static blok bir kez çalışır. (var, Java 10+: tipi sağdan çıkarır; String... = String[].)

Yığın (stack)Heapmain()d1?d2?Kopek #1adinull

new Kopek("Kara"): nesne için yer ayrılır, adi = null.

Yığın (stack)HeapKopek(adi)thisadi"Kara"main()d1?d2?Kopek #1adinull

Yapıcının gövdesinden önce örnek ilklendirici bloğu çalışır.

Yığın (stack)HeapKopek(adi)thisadi"Kara"main()d1?d2?Kopek #1adi"Kara"

Şimdi yapıcı gövdesi: this.adi = adi.

Yığın (stack)HeapKopek(adi)thisadi"Kara"main()d1?d2?Kopek #1adi"Kara"

Yapıcı adı yazdırır: Kara.

Yığın (stack)Heapmain()d1d2Kopek #1adi"Kara"Kopek #2adi"Gece"

İkinci nesne: ilklendirici + yapıcı yeniden; static blok tekrar çalışmaz.

Yığın (stack)Heaphavla()thismain()d1d2Kopek #1adi"Kara"Kopek #2adi"Gece"

havla() bir metin döndürür ama değer kullanılmıyor: hiçbir şey yazılmaz.

public class Kopek {
  String adi;                 // alan
  Kopek(String adi) {         // yapıcı metot
    this.adi = adi;
    System.out.println(adi);
  }
  String havla() {            // örneğe ait metot
    return adi + " haw haw haw!";
  }
  static {                    // sınıfa ait ilklendirici
    System.out.println("Köpekler!");
  }
  {                           // örneğe ait ilklendirici
    System.out.println("Köpek oluşturuluyor.");
  }
  public static void main(String... strings) {
    var d1 = new Kopek("Kara");
    var d2 = new Kopek("Gece");
    d2.havla();
  }
}

Metotlar

Metot Türleri

  • Metotlar, sınıf içinde tanımlanan, belirli bir işi yapan kod bloklarıdır; sınıfın davranışını tanımlar.
  • Örneğe ait metotlar (instance methods) bir nesneyle ilişkilidir: telefon.aramaYap(...). O nesnenin alanlarını kullanır.
  • Sınıfa ait metotlar (static) sınıfın kendisiyle ilişkilidir, tüm nesnelerde ortaktır: CepTelefonu üzerinden.
  • Static metotlar belirli bir nesneye bağlı olmadığı için nesneye özgü verilere (model gibi) doğrudan erişemez.
public class CepTelefonu {
  private String model;
  private static String isletimSistemi = "Sürüm 1";

  // Örneğe ait metot
  public void aramaYap(String numara) {
    System.out.println(model + " arıyor: " + numara);
  }

  // Örneğe ait metot
  public void mesajGonder(String alici, String mesaj) {
    System.out.println(alici + " <- " + mesaj);
  }

  // Sınıfa ait metot (static)
  public static void sistemiGuncelle(String yeniSurum) {
    isletimSistemi = yeniSurum;
  }
}

Metotlar

Metot Örneği: Eposta

public class Eposta {
  public boolean gonder(String alici, String konu,
             String icerik) {
    // Gerçek gönderim yerine bir benzetim
    if (alici == null || !alici.contains("@")) {
      return false;               // başarısız
    }
    System.out.println(alici + " <- " + konu);
    return true;                    // başarılı
  }

  public static void main(String[] args) {
    Eposta e = new Eposta();
    boolean s1 = e.gonder("ali@ornek.com", "Ödev", "Ek");
    boolean s2 = e.gonder("ali.ornek.com", "Ödev", "Ek");
    System.out.println(s1 + " " + s2);
  }
}
gonder metodu
  • Ad: gonder
  • Parametreler: üç String: alıcı, konu, içerik
  • Dönüş tipi: boolean, gönderim başarılı mı?
Çıktı
ali@ornek.com <- Ödev
true false

boolean döndüren metodun her yolu bir return ile bitmelidir; gövdesi yalnızca yorum olan bir metot missing return statement hatası verir.

Metotlar

Örneğe Ait Alanlar ve Metotlar

  • Sınıf içinde static anahtar sözcüğü olmadan tanımlanırlar.
  • Her nesne, alanların kendi kopyasına sahiptir; nesneler farklı verilere sahip olabilir.
  • Alanlar nesnenin özelliklerini, metotlar o nesnenin davranışını temsil eder.
  • Kullanabilmek için önce nesne oluşturmak gerekir: new, sonra nesne.metot().
  • Metot kodu tüm nesneler için tektir; her çağrıda hangi nesnenin verisiyle çalışacağını this belirler.
Örneğe aitstatic
Kime ait?NesneyeSınıfa
Çağrınesne.metot()Sinif.metot()
Nesne gerekir mi?EvetHayır
this var mı?EvetHayır
Örnekstr.length()Math.sqrt(x)
selamVer() kodusınıfta tek kopyaogrenci1 nesnesiad = "Ali"thisogrenci2 nesnesiad = "Ayşe"this

Metotlar

Nokta İşleci

public class Telefon {
  String numara;
  public Telefon(String numara) {
    this.numara = numara;
  }
  public void aramaYap(Telefon telefon) {
    System.out.println(numara + " arıyor: " + telefon.numara);
  }
  public void mesajGonder(Telefon telefon, String mesaj) {
    System.out.println(telefon.numara + " <- " + mesaj);
  }
  public void kameraAc() {
    System.out.println(numara + " kamera açtı.");
  }
  public static void main(String[] args) {
    Telefon telefon1 = new Telefon("5551234567");
    Telefon telefon2 = new Telefon("5051234567");
    telefon1.aramaYap(telefon2);
    telefon2.mesajGonder(telefon1, "Merhaba!");
    telefon1.kameraAc();
  }
}
Çıktı
5551234567 arıyor: 5051234567
5551234567 <- Merhaba!
5551234567 kamera açtı.
  • Nesne oluşturulduktan sonra alan ve metotlarına nokta işleci ile erişilir: nesne.metot(...), nesne.alan.
  • telefon1.aramaYap(...): telefon1 arar; metotta numara telefon1'in, telefon.numara telefon2'nin numarasıdır.
  • Bir nesne başka bir nesneyi parametre olarak alabilir.

Metotlar

Dikdörtgen Sınıfı

public class Dikdortgen {
  private double uzunluk;     // dikdörtgenin uzunluğu
  private double genislik;    // dikdörtgenin genişliği

  // Yapıcı metot
  public Dikdortgen(double uzunluk, double genislik) {
    this.uzunluk = uzunluk;
    this.genislik = genislik;
  }

  public double alanHesapla() {      // alanı hesaplar
    return uzunluk * genislik;
  }

  public double cevreHesapla() {     // çevreyi hesaplar
    return 2 * (uzunluk + genislik);
  }
}
  • Alanlar private: dışarıdan yalnızca metotlarla kullanılır.
  • Yapıcı, iki kenarı alır ve nesneye kaydeder.
  • alanHesapla() ve cevreHesapla() parametre almaz: ihtiyaç duydukları veriler nesnenin içinde.
  • Prosedürel karşılığı alanHesapla(5.0, 3.0) olurdu; nesneyle dikdortgen.alanHesapla().

Metotlar · Adım adım kod izleme

Dikdörtgen: Adım Adım

Yığın (stack)Heapmain()dikdortgenkarealan?cevre?Dikdortgen #1uzunluk5.0genislik3.0Dikdortgen #2uzunluk5.0genislik5.0

İki nesne, her biri kendi uzunluk ve genislik değerleriyle.

Yığın (stack)HeapalanHesapla()thismain()dikdortgenkarealan?cevre?Dikdortgen #1uzunluk5.0genislik3.0Dikdortgen #2uzunluk5.0genislik5.0

dikdortgen.alanHesapla(): this = #1, sonuç 5.0 × 3.0 = 15.0.

Yığın (stack)Heapcevre...()thismain()dikdortgenkarealan15.0cevre?Dikdortgen #1uzunluk5.0genislik3.0Dikdortgen #2uzunluk5.0genislik5.0

alan = 15.0. cevreHesapla(): 2 × (5.0 + 3.0) = 16.0.

Yığın (stack)Heapmain()dikdortgenkarealan15.0cevre16.0Dikdortgen #1uzunluk5.0genislik3.0Dikdortgen #2uzunluk5.0genislik5.0

double değerler 15.0 biçiminde yazılır.

Yığın (stack)HeapalanHesapla()thismain()dikdortgenkarealan25.0cevre20.0Dikdortgen #1uzunluk5.0genislik3.0Dikdortgen #2uzunluk5.0genislik5.0

Aynı metotlar, bu kez this = #2 (kare): 25.0 ve 20.0. Eski değerlerin üzerine yazılır.

Yığın (stack)Heapmain()dikdortgenkarealan25.0cevre20.0Dikdortgen #1uzunluk5.0genislik3.0Dikdortgen #2uzunluk5.0genislik5.0

İkinci satır yazdırılır. Uzun bir deyim iki satıra bölünebilir; ; gelene kadar sürer.

public class DikdortgenTesti {
  public static void main(String[] args) {
    Dikdortgen dikdortgen = new Dikdortgen(5.0, 3.0);
    Dikdortgen kare = new Dikdortgen(5.0, 5.0);
    double alan = dikdortgen.alanHesapla();
    double cevre = dikdortgen.cevreHesapla();
    System.out.println("Alanı: " + alan
        + " Çevresi: " + cevre);
    alan = kare.alanHesapla();
    cevre = kare.cevreHesapla();
    System.out.println("Alanı: " + alan
        + " Çevresi: " + cevre);
  }
}

static Üyeler

static Değişkenler ve Metotlar

public class Matematik {
  // Statik toplama metodu
  public static int toplama(int sayi1, int sayi2) {
    return sayi1 + sayi2;
  }

  public static void main(String[] args) {
    int sonuc = Matematik.toplama(5, 3);
    System.out.println("Toplama Sonucu: " + sonuc);
    System.out.println(Math.max(4, 9));
    System.out.println(Math.sqrt(16.0));
  }
}
  • static anahtar sözcüğüyle tanımlanır; sınıfa aittir.
  • static üyelere erişmek için nesne oluşturmaya gerek yoktur; sınıf adı ve nokta kullanılır: SinifAdi.alanAdi, SinifAdi.metotAdi(argumanlar).
  • Nesne üzerinden de erişilebilir (nesne.alanAdi), ama tercih edilmez: okuyan kişi üyenin nesneye ait olduğunu sanır.
  • Hazır örnekler: Math.max(), Math.sqrt(), Math.PI, Integer.parseInt() ve main.
Çıktı
Toplama Sonucu: 8
9
4.0

static Üyeler

static Kuralları

Nereden →Örnek alan/metot kullanımıstatic alan/metot kullanımı
Örneğe ait metottan✓ doğrudan (ad, this.ad)✓ doğrudan
static metottan (main dahil)✗ ancak bir nesne üzerinden (ogr.ad)✓ doğrudan
public class Selam {
  private String ad = "Ali";
  public void selamVer() {
    System.out.println("Merhaba " + ad);
  }
  public static void main(String[] args) {
    selamVer();
  }
}
error: non-static method selamVer() cannot be referenced from a static context
public class Selam2 {
  private String ad = "Ali";
  public static void yaz() {
    System.out.println(ad);
  }
}
error: non-static variable ad cannot be referenced from a static context

Çözüm: çağrı nesne üzerinden yapılır (new Selam().selamVer();) ya da metot static yapılır.

Referanslar ve this

Referans Atama

  • Java'da nesneler referanslar (adresler) aracılığıyla işlenir.
  • araba2 = araba1; nesneyi kopyalamaz, referansı kopyalar: iki değişken aynı nesneyi işaret eder (takma ad, alias).
  • Biri üzerinden yapılan değişiklik diğerinden de görünür.
Kütüphane etiketiRaftaki etiket kitabın kendisi değil, yerini gösterir.
Araba anahtarıAnahtar arabayı işaret eder; iki anahtar aynı arabayı açar.
public class Araba {
  private String marka;

  public Araba(String marka) {
    this.marka = marka;
  }

  public String getMarka() {
    return marka;
  }

  public void setMarka(String marka) {
    this.marka = marka;
  }

}

Referanslar ve this · Adım adım kod izleme

Referans Atama: Adım Adım

Yığın (stack)Heapmain()araba1araba2?Araba #1marka"Toyota"

Bir nesne oluşturulur; araba1 onu gösterir.

Yığın (stack)Heapmain()araba1araba2Araba #1marka"Toyota"

araba2 = araba1: referans kopyalanır. Hâlâ tek nesne var.

Yığın (stack)Heapmain()araba1araba2Araba #1marka"Toyota"

İki değişken aynı nesneyi okur: ikisi de Toyota.

Yığın (stack)HeapsetMarka()thismarka"Ford"main()araba1araba2Araba #1marka"Ford"

araba2.setMarka("Ford") ortak nesneyi değiştirir.

Yığın (stack)Heapmain()araba1araba2Araba #1marka"Ford"

araba1 üzerinden okuyunca da Ford: değişiklik paylaşılır.

Yığın (stack)Heapmain()araba1nullaraba2Araba #1marka"Ford"

araba1 = null: yalnızca bu değişkenin bağı kopar; nesne silinmez, araba2 onu göstermeye devam eder.

Yığın (stack)Heapmain()araba1nullaraba2Araba #1marka"Ford"

Nesneyi gösteren son referans da kaybolursa nesne çöp toplayıcı (garbage collector) tarafından silinir.

public static void main(String[] args) {
  Araba araba1 = new Araba("Toyota");
  Araba araba2 = araba1;
  System.out.println("Araba 1: " + araba1.getMarka());
  System.out.println("Araba 2: " + araba2.getMarka());
  araba2.setMarka("Ford");
  System.out.println("Araba 1: " + araba1.getMarka());
  araba1 = null;
  System.out.println("Araba 2: " + araba2.getMarka());
}

Referanslar ve this

null ve NullPointerException

public class Bos {
  String ad;

  public static void main(String[] args) {
    Bos b = null;
    System.out.println(b.ad.length());
  }
}
Exception in thread "main" java.lang.NullPointerException: Cannot read field "ad" because "<local1>" is null
    at Bos.main(Bos.java:6)

Yerel değişken hiç değer verilmeden kullanılırsa program derlenmez: error: variable sb might not have been initialized

  • null, referans değişkeninin hiçbir nesneyi göstermediği anlamına gelir.
  • null bir referans üzerinden alan okumak ya da metot çağırmak çalışma zamanında NullPointerException fırlatır.
  • Önlem: kullanmadan önce denetim: if (b != null) { ... }
  • Hiçbir referansın göstermediği nesneler JVM'in çöp toplayıcısı tarafından otomatik silinir; Java'da nesneyi elle silmek gerekmez.
main()bnullb.ad→ NullPointerExceptionreferansı kalmayan nesneçöp toplayıcı siler

Referanslar ve this

this Anahtar Sözcüğü

public class Golge {
  private String ad;

  public Golge(String ad) {
    ad = ad;            // this unutuldu!
  }

  public static void main(String[] args) {
    Golge g = new Golge("Ali");
    System.out.println(g.ad);
  }
}
Çıktı
null
  • this, metodun çağrıldığı nesneyi işaret eden referanstır.
  • static metotlarda kullanılamaz (orada nesne yoktur).
  • En sık yapıcılarda, alan adı ile parametre adı aynı olduğunda kullanılır: this.ad = ad;
  • Soldaki kodda this unutulmuş: ad = ad; parametreyi kendine atar, alan null kalır. Derleyici hata vermez!
  • this(...) ise aynı sınıfın başka bir yapıcısını çağırır.
Golge("Ali") çerçevesiad"Ali"thisad = adparametre kendineGolge nesnesiadnullthis.ad = ad yazılsaydı buraya "Ali" giderdi

Referanslar ve this

this ile Nesneyi Aktarmak

public class Takim {
  private String ad;
  public Takim(String ad) {
    this.ad = ad;
  }
  public void oyuncuEkle(Oyuncu oyuncu) {
    oyuncu.takimaKatil(this);   // bu nesne
  }
  public String getAd() {
    return ad;
  }
  public static void main(String[] args) {
    Takim takim = new Takim("Giresunspor");
    Oyuncu oyuncu = new Oyuncu("Mert");
    takim.oyuncuEkle(oyuncu);
  }
}
  • this, o anki nesneyi başka bir metoda parametre olarak iletmek için kullanılır.
  • takim.oyuncuEkle(oyuncu) içinde this = takim nesnesi; takimaKatil(this) ile oyuncuya verilir.
  • Aynı dosyada ikinci sınıf (public değil):
class Oyuncu {
  private String ad;
  Oyuncu(String ad) {
    this.ad = ad;
  }
  void takimaKatil(Takim takim) {
    String t = takim.getAd();
    System.out.println(ad + " -> " + t);
  }
}
Çıktı
Mert -> Giresunspor

Referanslar ve this · Adım adım kod izleme

this ile Selam: Adım Adım

Yığın (stack)HeapOgrenci(ad)thisad"Ali"main()ogrenci1?ogrenci2?Ogrenci #1ad"Ali"

Yapıcıda this yeni nesnedir: this.ad (alan) = ad (parametre).

Yığın (stack)Heapmain()ogrenci1ogrenci2Ogrenci #1ad"Ali"Ogrenci #2ad"Ayşe"

İkinci nesne de aynı yapıcıyla oluşur; o sırada this = #2 idi.

Yığın (stack)HeapselamVer()thismain()ogrenci1ogrenci2Ogrenci #1ad"Ali"Ogrenci #2ad"Ayşe"

ogrenci1.selamVer(): noktanın solundaki nesne this olur → "Ali".

Yığın (stack)HeapselamVer()thismain()ogrenci1ogrenci2Ogrenci #1ad"Ali"Ogrenci #2ad"Ayşe"

Aynı kod, farklı this → "Ayşe". Burada this.ad yerine ad yazmak da aynıdır.

public class Ogrenci {
  private String ad;

  public Ogrenci(String ad) {
    this.ad = ad;
  }

  public void selamVer() {
    System.out.println("Merhaba, ben " + this.ad);
  }

  public static void main(String[] args) {
    Ogrenci ogrenci1 = new Ogrenci("Ali");
    Ogrenci ogrenci2 = new Ogrenci("Ayşe");
    ogrenci1.selamVer();
    ogrenci2.selamVer();
  }
}

Referanslar ve this

this(...) ile Yapıcı Zinciri

  • this(...) aynı sınıfın başka bir yapıcısını çağırır. Ortak ilk değer atamaları tek bir yapıcıda toplanır; öteki yapıcılar ona eksik argümanları ekleyerek devreder.
  • this(...) yapıcının ilk satırı olmalıdır; başka bir deyimden sonra yazılırsa derlenmez.
  • Çağrılan yapıcının gövdesi önce biter, sonra çağıranın kalan satırları çalışır; zincir kaç yapıcıdan geçerse geçsin tek bir nesne kurulur.
  • Yapıcılar birbirini döngüsel çağırırsa derleyici bunu yakalar.
class Calisan {
  private String ad;
  private double maas;
  Calisan(String ad) {
    this(ad, 20000.0);   // aynı sınıfın yapıcısı
  }
  Calisan(String ad, double maas) {
    this.ad = ad;        // ilk değerler tek yerde
    this.maas = maas;
  }
}

İlk satırda değil: A() { x = 1; this(2); }

error: call to this must be first statement in constructor

Döngü: A() { this(1); } ve A(int x) { this(); }

error: recursive constructor invocation

Referanslar ve this · Adım adım kod izleme

new Kitap("Nutuk", "Atatürk"): Adım Adım

Yığın (stack)Heapmain()k2?Kitap nesnesiadnullyazarnullsayfaSayisi0

new heap'te yeni bir nesne ayırır; alanlar varsayılan değerleri alır: null, null, 0.

Yığın (stack)HeapKitap(ad, yazar)thisad"Nutuk"yazar"Atatürk"main()k2?Kitap nesnesiadnullyazarnullsayfaSayisi0

Argümanlar iki String olduğu için iki parametreli yapıcı çalışır. this, yeni nesneyi gösterir.

Yığın (stack)HeapKitap(ad)thisad"Nutuk"Kitap(ad, yazar)thisad"Nutuk"yazar"Atatürk"main()k2?Kitap nesnesiadnullyazarnullsayfaSayisi0

this(ad): zincirleme. Tek parametreli yapıcı, aynı nesne için çağrılır.

Yığın (stack)HeapKitap(ad)thisad"Nutuk"Kitap(ad, yazar)thisad"Nutuk"yazar"Atatürk"main()k2?Kitap nesnesiad"Nutuk"yazarnullsayfaSayisi0

this.ad = ad: parametredeki değer nesnenin ad alanına yazılır.

Yığın (stack)HeapKitap(ad, yazar)thisad"Nutuk"yazar"Atatürk"main()k2?Kitap nesnesiad"Nutuk"yazar"Atatürk"sayfaSayisi0

İç yapıcı bitti. Kalan satır: this.yazar = yazar.

Yığın (stack)Heapmain()k2Kitap nesnesiad"Nutuk"yazar"Atatürk"sayfaSayisi0

Yapıcılar bitti; new ifadesinin değeri nesnenin referansıdır. k2 artık nesneyi gösterir.

Yığın (stack)Heapmain()k2Kitap nesnesiad"Nutuk"yazar"Atatürk"sayfaSayisi0

Nokta işleciyle alanlar okunur: Nutuk / Atatürk / 0.

class Kitap {
  String ad;
  String yazar;
  int sayfaSayisi;
  public Kitap(String ad) {
    this.ad = ad;
  }
  public Kitap(String ad, String yazar) {
    this(ad);  // yapıcı zincirleme
    this.yazar = yazar;
  }
}
// main içinde:
Kitap k2 = new Kitap("Nutuk", "Atatürk");
System.out.println(k2.ad + " / "
    + k2.yazar + " / " + k2.sayfaSayisi);

Nesneleri Karşılaştırma

== ve equals()

  • Değişkenler yalnızca nesnelere ait referansları saklar.
  • == işleci nesnelerin alanları yerine bellek adreslerini karşılaştırır: iki değişken aynı nesneyi mi gösteriyor?
  • İki nesnenin içerik eşitliği için tüm özellikleri karşılaştıran equals() kullanılır; kendi sınıflarımızda yeniden yazılmalıdır.
  • String ve wrapper'lar da nesnedir: klavyeden okunan "Java" ile "Java" sabiti == ile false, equals ile true verir.
  • equals, hashCode, toString ve getClass her sınıfa Object'ten gelir; equals yeniden yazılınca hashCode da yazılmalıdır.
Yığın (stack)Heapmain()k1k2k3Kisi #1ad"Ali"yas20Kisi #2ad"Ali"yas20
İfadeSonuç
k1 == k3true: aynı nesne
k1 == k2false: farklı nesneler
k1.equals(k2)true: aynı içerik*

* equals yeniden yazıldıysa; yoksa Object'in sürümü == gibi davranır.

Wrapper Sınıflar

Wrapper Sınıflar

İlkel tipWrapper sınıf
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean
  • Wrapper (sarmalayıcı) sınıflar, temel veri tiplerini nesne olarak temsil eder.
  • Bazı yerlerde nesne gerekir: ArrayList<Integer> gibi jenerik koleksiyonlar ilkel tip alamaz.
  • İlkel tipe null atanamaz; wrapper değişkene atanabilir ("değer yok").
  • Yardımcı metotlar sağlar: Integer.parseInt("12"), Integer.MAX_VALUE, Character.isDigit(c).
  • İlkel tipler daha hızlı ve az bellek kullanır; gerekmedikçe ilkel tip tercih edilir.
  • Autoboxing ve unboxing dönüşümlerine dikkat edilmelidir.
YığınHeapint sayi42Integer wInteger nesnesivalue = 42değerin kendisiw = null da olabilir

Wrapper Sınıflar

Autoboxing ve Unboxing

public class Sarmalayici {
  public static void main(String[] args) {
    // int tipinde bir değişken
    int sayi = 42;
    // Integer wrapper sınıfı kullanımı
    Integer wrapperSayi = Integer.valueOf(sayi);
    // Autoboxing (otomatik kutulama)
    Integer wrapperSayi2 = sayi;
    // Unboxing (açık ve otomatik)
    int sayi2 = wrapperSayi2.intValue();
    int sayi3 = wrapperSayi2;
    System.out.println(sayi2 + sayi3);
    System.out.println(wrapperSayi.equals(wrapperSayi2));
    System.out.println(Integer.parseInt("123") + 1);
    System.out.println(Integer.MAX_VALUE);
    System.out.println(Character.isDigit('7'));
    System.out.println(Double.parseDouble("2.5") * 2);
    Integer bos = null;      // int bos = null; derlenmez
    System.out.println(bos);
  }
}
  • Autoboxing: ilkel tip → wrapper, otomatik. Unboxing: wrapper → ilkel tip.
  • Açık biçimleri: Integer.valueOf(sayi), w.intValue().
Çıktı
84
true
124
2147483647
true
5.0
null

Wrapper Sınıflar

Wrapper Tuzakları

import java.util.ArrayList;
public class Tuzaklar {
  public static void main(String[] args) {
    ArrayList<Integer> liste = new ArrayList<>();
    liste.add(5);                 // autoboxing: 5 -> Integer
    int ilk = liste.get(0);       // unboxing: Integer -> int
    System.out.println(ilk + 1);
    Integer a = 127, b = 127;
    Integer c = 128, d = 128;
    System.out.println(a == b);
    System.out.println(c == d);
    System.out.println(c.equals(d));
    Integer bos = null;
    int x = bos;                  // NullPointerException
  }
}
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "<local7>" is null
Çıktı
6
true
false
true
  • Wrapper nesnelerini == ile karşılaştırmak yanlıştır: == referans karşılaştırır. −128…127 arası değerler önbellekten aynı nesne olarak gelir; 128 için false.
  • Karşılaştırmada her zaman equals() kullanılır.
  • null bir wrapper'ı açmak (unboxing) NullPointerException fırlatır.

Wrapper Sınıflar · Adım adım kod izleme

Integer Önbelleği: Kod İzleme

YığınHeapmain()abönbellek: 127value127

Otomatik kutulama Integer.valueOf(127) çağırır. −128…127 arası değerler önbellekte hazırdır: a ve b aynı nesneyi alır.

YığınHeapmain()abcdönbellek: 127value127Integer #1value128Integer #2value128

128 önbellek aralığının dışında: valueOf her seferinde yeni bir nesne oluşturur.

YığınHeapmain()abcdönbellek: 127value127Integer #1value128Integer #2value128a == b → true (aynı nesne)

== referansları karşılaştırır; iki ok aynı nesneye gider: true.

YığınHeapmain()abcdönbellek: 127value127Integer #1value128Integer #2value128c == d → false (#1 ≠ #2)

Değerler aynı (128) ama nesneler farklı: false. Wrapper'ları == ile karşılaştırmanın tuzağı budur.

YığınHeapmain()abcdönbellek: 127value127Integer #1value128Integer #2value128c.equals(d) → 128 == 128 → true

Integer.equals içerideki int değerleri karşılaştırır: true.

YığınHeapmain()abcdt256önbellek: 127value127Integer #1value128Integer #2value128c.intValue() + d.intValue() = 256

+ nesnelerle çalışmaz: ikisi de kutudan çıkarılır (intValue()). t ilkel bir inttir, değeri yığında durur.

YığınHeapmain()abcdt256önbellek: 127value127Integer #1value128Integer #2value128

İlkel t doğrudan yazdırılır: 256.

YığınHeapmain()abcdt256bosnullönbellek: 127value127Integer #1value128Integer #2value128

Wrapper değişkene null atanabilir; int bos = null ise derlenmezdi.

YığınHeapmain()abcdt256bosnullx?önbellek: 127value127Integer #1value128Integer #2value128bos.intValue() → NullPointerException

int x = bos gizlice bos.intValue() olur. Gösterilen nesne yok: NullPointerException, program durur.

Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println(a == b);
System.out.println(c == d);
System.out.println(c.equals(d));
int t = c + d;
System.out.println(t);
Integer bos = null;
int x = bos;

Kayıt ve enum

Kayıtlar (Records)

  • Kayıt (record, Java 16+), yalnızca veri taşıyan sınıfları kısa ve temiz yazmak için tasarlanmış bir sınıf türüdür.
  • Değiştirilemez (immutable) nesneleri temsil eder: tüm alanlar private final'dır; set metodu yoktur.
  • Derleyici otomatik üretir: yapıcı, erişim metotları x() ve y() (adları get ile başlamaz), equals, hashCode, toString.
record Nokta(double x, double y) { }

Bu tek satır; iki alan, yapıcı, iki erişimci ve üç Object metodu içeren yaklaşık 30 satırlık bir sınıfa denktir.

public class KayitTesti {
  public static void main(String[] args) {
    Nokta nokta1 = new Nokta(1.0, 2.5);
    Nokta nokta2 = new Nokta(1.0, 2.5);
    boolean esitMi = nokta1.equals(nokta2);
    System.out.println(esitMi);
    System.out.println(nokta1 == nokta2);
    System.out.println(nokta1);
    System.out.println(nokta1.x() + nokta1.y());
  }
}
Çıktı
true
false
Nokta[x=1.0, y=2.5]
3.5
n.x = 3.0;   →   error: x has private access in Nokta

Kayıt ve enum

enum (Numaralandırma Tipi)

enum HaftaGunleri {
  PAZARTESI, SALI, CARSAMBA, PERSEMBE,
  CUMA, CUMARTESI, PAZAR
}
public class GunTesti {
  public static void main(String[] args) {
    HaftaGunleri[] tumGunler = HaftaGunleri.values();
    HaftaGunleri persembe = HaftaGunleri.valueOf("PERSEMBE");
    System.out.println(tumGunler.length + " gün");
    System.out.println(persembe + " " + persembe.ordinal());
    for (HaftaGunleri gun : tumGunler) {
      boolean haftaSonu = gun == HaftaGunleri.CUMARTESI
          || gun == HaftaGunleri.PAZAR;
      if (haftaSonu) {
        System.out.println(gun + ": hafta sonu");
      }
    }
  }
}
Çıktı
7 gün
PERSEMBE 3
CUMARTESI: hafta sonu
PAZAR: hafta sonu
  • enum, sabit ve sınırlı değerleri temsil eden özel bir türdür.
  • values() tüm değerleri dizi olarak verir; üzerinde döngü kurulabilir.
  • valueOf metinden değere çevirir; ordinal() 0'dan başlayan sıra. Değerler == ile karşılaştırılır.

İç Sınıflar

İç Sınıflar (Inner Classes)

  • İç sınıf, bir sınıfın içinde tanımlanan sınıftır. Dış sınıfın alanlarına ve metotlarına (private olanlar dahil) doğrudan erişebilir.
  • Yalnızca bir sınıfın işine yarayan yardımcı sınıfları gruplamak için kullanılır; grafik arayüzlerde olay dinleyici (listener) sınıfları için çok yaygındır.
TürNerede tanımlanır?Nasıl oluşturulur?
static iç sınıfSınıf gövdesinde, static ileDış sınıf nesnesi olmadan: new Outer.StaticInner()
Üye iç sınıfSınıf gövdesinde, static olmadanBir dış sınıf nesnesi üzerinden: outer.new MemberInner()
Yerel iç sınıfBir metodun içindeYalnızca o metodun içinden
Anonim iç sınıfBir ifadenin içinde, adsızTanımlandığı yerde tek nesne; bir arayüzü veya soyut sınıfı uygular

İç Sınıflar

static İç Sınıf

public class Outer {
  // Dış sınıfın içinde statik bir iç sınıf
  static class StaticInner {
    void display() {
      System.out.println("Statik İç Sınıf");
    }
  }

  public static void main(String[] args) {
    // Dış sınıf örneği oluşturmadan erişim
    Outer.StaticInner staticInner = new Outer.StaticInner();
    staticInner.display();
  }
}
Çıktı
Statik İç Sınıf
  • static anahtar sözcüğüyle tanımlanır.
  • Dış sınıfın bir nesnesi olmadan oluşturulabilir: new Outer.StaticInner().
  • Dış sınıfın yalnızca static üyelerine doğrudan erişebilir.

İç Sınıflar

Üye İç Sınıf

public class Outer {
  private int sayi = 5;          // dış sınıfın özel alanı

  class MemberInner {            // üye iç sınıf
    void display() {
      System.out.println("Üye İç Sınıf, sayi = " + sayi);
    }
  }

  public static void main(String[] args) {
    // Dış sınıf örneği üzerinden üye iç sınıfa erişim
    Outer outer = new Outer();
    Outer.MemberInner memberInner = outer.new MemberInner();
    memberInner.display();
  }
}
Çıktı
Üye İç Sınıf, sayi = 5
  • Dış sınıfın bir üyesi olarak (static olmadan) tanımlanır.
  • Her üye iç sınıf nesnesi bir dış nesneye bağlıdır: outer.new MemberInner(). Bu yüzden private sayi'yi okuyabilir.
  • main içinde doğrudan new MemberInner() derlenmez:
error: non-static variable this cannot be referenced from a static context

İç Sınıflar · Adım adım kod izleme

Üye İç Sınıf: Kod İzleme

YığınHeapmain()o1Outer #1sayi5

İlk dış nesne: kendi sayi alanı 5.

YığınHeapmain()o1o2Outer #1sayi5Outer #2sayi5

İkinci dış nesne; o da 5 ile başlar. İki ayrı sayi var.

YığınHeapmain()o1o2Outer #1sayi5Outer #2sayi8

main de Outer'ın içinde olduğu için private alana yazabilir: yalnızca #2 değişir.

YığınHeapmain()o1o2mOuter #1sayi5Outer #2sayi8MemberInner #3Outer.this

o2.new MemberInner(): iç nesne, onu oluşturan dış nesnenin referansını gizli bir alanda (Outer.this) saklar.

YığınHeapdisplay()thismain()o1o2mOuter #1sayi5Outer #2sayi8MemberInner #3Outer.this

m.display(): metotta this iç nesnedir (#3). İç sınıfın kendi sayi alanı yok.

YığınHeapdisplay()thismain()o1o2mOuter #1sayi5Outer #2sayi8MemberInner #3Outer.thissayi = Outer.this.sayi = 8

sayi, Outer.this.sayi demektir: ok #2'ye gider, 8 yazılır. o1.new MemberInner() olsaydı 5 yazılırdı.

public class Outer {
    private int sayi = 5;
    class MemberInner {
        void display() {
            System.out.println("sayi = " + sayi);
        }
    }
    public static void main(String[] args) {
        Outer o1 = new Outer();
        Outer o2 = new Outer();
        o2.sayi = 8;
        Outer.MemberInner m = o2.new MemberInner();
        m.display();
    }
}

İç Sınıflar

Yerel İç Sınıf

public class Outer {
  void outerMethod() {
    class LocalInner {         // metodun içinde tanımlanır
      void display() {
        System.out.println("Yerel İç Sınıf");
      }
    }
    // Yerel iç sınıfa yalnızca bu metodun içinden erişilir
    LocalInner localInner = new LocalInner();
    localInner.display();
  }

  public static void main(String[] args) {
    Outer outer = new Outer();
    outer.outerMethod();
  }
}
Çıktı
Yerel İç Sınıf
  • Bir metodun içinde tanımlanır; yalnızca o metodun içinden kullanılabilir.
  • Metot dışında LocalInner adı bilinmez.
  • Bir metodun içinde birkaç kez gereken küçük bir yardımcı tip için kullanılır.

İç Sınıflar

Anonim İç Sınıf

interface MyInterface {
  void myMethod();
}

public class Outer {
  public static void main(String[] args) {
    // Genellikle arayüzleri veya soyut sınıfları uygular
    MyInterface myInterface = new MyInterface() {
      @Override
      public void myMethod() {
        System.out.println("Anonim İç Sınıf");
      }
    };
    myInterface.myMethod();
  }
}
Çıktı
Anonim İç Sınıf
  • Adı olmayan sınıftır; tanımlandığı yerde tek bir nesnesi oluşturulur.
  • Genellikle bir arayüzü (interface) veya soyut sınıfı uygular: new ArayuzAdi() { ... }; Sondaki ; atama deyimine aittir.
  • Tek metotlu arayüzler için Java 8+ lambda daha kısadır: () -> ...

Sınıf Türleri ve Tasarım

Sınıflar ve Tipler

interface Printable { ... }
interface Runner { ... }
class Hayvan implements Printable, Serializable { ... }
class Kopek extends Hayvan implements Runner { ... }
var kazanan = new Kopek(...);
  • Bir nesne tek bir sınıfa ait olabilir, ama birçok türe sahip olabilir.
  • kazanan yalnızca Kopek sınıfına aittir.
  • Ama tipleri: Kopek, Runner, Hayvan, Printable, Serializable, Object; hepsi için instanceof true verir.
  • Bu, çok biçimliliğin temelidir.
Object«interface»Printable«interface»SerializableHayvan«interface»RunnerKopekextendsextends

Düz çizgi + boş üçgen: kalıtım (extends); kesikli: arayüzü uygulama (implements).

Sınıf Türleri ve Tasarım

Sınıf Çeşitleri

Sınıf, bir nesnenin yapısını ve davranışını tanımlayan bir şablondur. Amaçlarına göre farklı sınıf çeşitleri vardır:

ÇeşitÖzellikÖrnek
Numaralandırma (enum)Sabit bir nesne kümesine sahiptirenum Gun { PAZARTESI, SALI, ... }
SingletonYalnızca bir nesnesi oluşturulabilirprivate yapıcı + static tek nesne
Soyut (abstract)Kendi nesnesi oluşturulamazabstract class Sekil
Mühürlü (sealed, Java 17+)Alt sınıfları sabit bir kümedirsealed interface Hareket permits Yuru, Kos
FinalAlt sınıf türetilemezfinal class String
Veri (record)Nesneleri değiştirilemez (immutable)record Nokta(double x, double y)
Araç (utility)Yalnızca static metotlar içerirMath, Arrays
Uygulama (application)main metodunu içerirProgramın başladığı sınıf

Sınıf Türleri ve Tasarım

Sınıf Çeşitleri: Örnek

final class Araclar {             // araç ve final sınıf
  private Araclar() { }         // nesne oluşturulamaz
  static int kare(int x) { return x * x; }
}
class Ayarlar {                   // singleton
  private static final Ayarlar TEK = new Ayarlar();
  private Ayarlar() { }
  static Ayarlar getir() { return TEK; }
}
abstract class Sekil {            // soyut sınıf
  abstract double alan();
}
// mühürlü (sealed, Java 17+)
sealed interface Hareket permits Yuru, Kos { }
final class Yuru implements Hareket { }
final class Kos implements Hareket { }
public class Cesitler {           // uygulama sınıfı
  public static void main(String[] args) {
    System.out.println(Araclar.kare(7));
    System.out.println(Ayarlar.getir() == Ayarlar.getir());
  }
}
Çıktı
49
true
  • Araclar: private yapıcı ile nesne oluşturulamaz, yalnızca static metot; final ile türetilemez.
  • Ayarlar: tek nesne her seferinde aynıdır, bu yüzden == true.
  • new Sekil() derleme hatası verir (soyut); Hareket'i yalnızca Yuru ve Kos uygulayabilir.

Sınıf Türleri ve Tasarım

Tasarım Örneği: RasyonelSayi

public class RasyonelSayi {
  // Temsil: gizli alanlar
  private int pay, payda;
  // Tanımlama: public yapıcı ve metotlar
  public RasyonelSayi(int pay, int payda) {
    int e = ebob(Math.abs(pay), Math.abs(payda));
    this.pay = pay / e;
    this.payda = payda / e;
  }
  public RasyonelSayi topla(RasyonelSayi d) {
    int yeniPay = pay * d.payda + d.pay * payda;
    return new RasyonelSayi(yeniPay, payda * d.payda);
  }
  @Override
  public String toString() { return pay + "/" + payda; }
  // Gerçekleme ayrıntısı: gizli yardımcı metot
  private static int ebob(int a, int b) {
    while (b != 0) { int k = a % b; a = b; b = k; }
    return a;
  }
}
  • Tanımlama: public yapıcı, topla, toString.
  • Temsil: private int pay, payda; yapıcı kesri sadeleştirir.
  • Gerçekleme: metot gövdeleri ve gizli ebob yardımcısı (Öklid algoritması).
  • topla mevcut nesneyi değiştirmez, yeni bir nesne döndürür.

a = new RasyonelSayi(8, 10), b = new RasyonelSayi(2, 3); println(a) ve println(a.topla(b)):

Çıktı
4/5
22/15

Sınıf Türleri ve Tasarım · Adım adım kod izleme

RasyonelSayi: Kod İzleme

YığınHeapRasyonelSayi()pay6payda8e?main()a?Rasyonel #1pay0payda0

new RasyonelSayi(6, 8): nesnenin alanları önce 0; yapıcının parametreleri 6 ve 8.

YığınHeapebob()a6b8k-RasyonelSayi()pay6payda8e?main()a?Rasyonel #1pay0payda0

Gizli yardımcı ebob(6, 8) çağrılır (Öklid algoritması). Kullanıcı bu metodu göremez.

YığınHeapebob()a8b6k6RasyonelSayi()pay6payda8e?main()a?Rasyonel #1pay0payda0

6 % 8 = 6; a ← 8, b ← 6. İlk turda sayılar yer değiştirir.

YığınHeapebob()a6b2k2RasyonelSayi()pay6payda8e?main()a?Rasyonel #1pay0payda0

8 % 6 = 2; a ← 6, b ← 2.

YığınHeapebob()a2b0k0RasyonelSayi()pay6payda8e?main()a?Rasyonel #1pay0payda0

6 % 2 = 0; a ← 2, b ← 0. b == 0: döngü biter.

YığınHeapRasyonelSayi()pay6payda8e2main()a?Rasyonel #1pay3payda46/8 → 6/2 = 3, 8/2 = 4

ebob 2 döndürür; yapıcı kesri sadeleştirerek saklar: nesne 3/4. Temsil her zaman sade kalır.

YığınHeapmain()abRasyonel #1pay3payda4Rasyonel #2pay1payda6ebob(1, 6) = 1 → 1/6

Aynı adımlar (1, 6) için: ebob 1 döndürür, kesir zaten sade: 1/6.

YığınHeaptopla()thisdyeniPay22main()abRasyonel #1pay3payda4Rasyonel #2pay1payda63·6 + 1·4 = 22

a.topla(b): this = #1, d = #2. Aynı sınıf olduğu için d.payda gibi private alanlar okunabilir.

YığınHeapRasyonelSayi()pay22payda24e2topla()thisdyeniPay22main()abRasyonel #1pay3payda4Rasyonel #2pay1payda6Rasyonel #3pay11payda12ebob(22, 24) = 2 → 11/12

new RasyonelSayi(22, 24): ebob 24, 22, 2, 0 adımlarıyla 2 bulur; yeni nesne 11/12.

YığınHeapmain()abRasyonel #1pay3payda4Rasyonel #2pay1payda6Rasyonel #3pay11payda12topla() yeni nesne döndürdü; a hâlâ 3/4

Önce sonuç (#3), sonra a yazdırılır: topla mevcut nesneyi değiştirmez, yeni nesne döndürür.

public RasyonelSayi(int pay, int payda) {
    int e = ebob(Math.abs(pay), Math.abs(payda));
    this.pay = pay / e;
    this.payda = payda / e;
}
private static int ebob(int a, int b) {
    while (b != 0) { int k = a % b; a = b; b = k; }
    return a;
}
public RasyonelSayi topla(RasyonelSayi d) {
    int yeniPay = pay * d.payda + d.pay * payda;
    return new RasyonelSayi(yeniPay, payda * d.payda);
}
RasyonelSayi a = new RasyonelSayi(6, 8);   // main
RasyonelSayi b = new RasyonelSayi(1, 6);
System.out.println(a.topla(b) + " " + a);

Özet

Özet

KavramÖzü
Sınıf / nesneSınıf taslaktır; nesne new ile üretilen örneğidir.
YapıcıSınıfla aynı ad, dönüş tipi yok; yazılmazsa varsayılan yapıcı eklenir.
Örnek / static üyeÖrnek alanı her nesnede ayrı; static alan sınıfta tek ve ortak.
İlklendiricilerstatic { } bir kez; { } her nesnede, yapıcı gövdesinden önce.
Erişim ve gizlemeAlanlar private; get/set ile kontrollü erişim.
ReferansDeğişken nesneyi değil referansı tutar; atama referansı kopyalar.
this / this(...)Metodun çağrıldığı nesne (static metotta yok) / aynı sınıfın başka yapıcısı, ilk satırda.
== / equalsAynı nesne mi? / aynı içerik mi?
Wrapperint ↔ Integer: autoboxing ve unboxing.
record / enumDeğiştirilemez veri sınıfı / sabit değer kümesi.
İç sınıflarstatic, üye, yerel, anonim.

Özet

İlgili Sayfalar

Yığın ve Heap Gezgini

Simülatör: new ile oluşan nesneler, referans atama, this ve metot çerçeveleri yığında ve heap'te adım adım.

Çalışma Soruları

Yapıcı zinciri, ilklendirme sırası, static üyeler, referanslar, == ve equals, wrapper, enum ve iç sınıf soruları.

Özet

Sık Yapılan Hatalar (1)

Örnek metodu main'den nesnesiz çağırmakerror: non-static method selamVer() cannot be referenced from a static context Çağrı bir nesne üzerinden yapılır (new Selam().selamVer()); metot gerçekten nesneye bağlı değilse static yapılır.
Yapıcıya void yazmakerror: constructor Hata1 in class Hata1 cannot be applied to given types; public void Hata1(String m) yapıcı değil, sıradan metottur. Yapıcının dönüş tipi olmaz.
Yalnızca parametreli yapıcı varken new Urun()error: constructor Urun in class Urun cannot be applied to given types; Bir yapıcı yazılınca varsayılan yapıcı eklenmez; gerekiyorsa parametresiz yapıcı da yazılır.
new unutmakerror: cannot find symbol symbol: method Urun(String)Nesne oluşturmak için new Urun("Kalem") yazılmalıdır.

Özet

Sık Yapılan Hatalar (2)

private alana dışarıdan erişmekerror: hesapBakiyesi has private access in BankaHesabi Alana sınıfın get/set metotlarıyla erişilir.
static metotta thiserror: non-static variable this cannot be referenced from a static context Static metodun bir nesnesi yoktur.
this unutmak (gölgeleme)ad = ad; // derlenir, alan null kalırParametre alanı gölgeler; doğrusu this.ad = ad;.
this(...) ilk satırda değilerror: call to this must be first statement in constructor Öteki yapıcıya devretme yapıcının ilk deyimi olmalıdır.

Özet

Sık Yapılan Hatalar (3)

Nesneleri == ile karşılaştırmakk1 == k2 // falseİçerik equals() ile karşılaştırılır; String ve wrapper'lar dahil.
null referansı kullanmakNullPointerExceptionNesne oluşturulmadan veya null atandıktan sonra metot çağrılamaz; önce null denetimi yapılır.
Record alanını değiştirmeye çalışmakerror: x has private access in Nokta Record değiştirilemezdir; yeni değer için yeni bir nesne oluşturulur.
Üye iç sınıfı static main'de oluşturmakerror: non-static variable this cannot be referenced from a static context Doğrusu outer.new MemberInner(); ya da iç sınıf static yapılır.

Özet

Örnek Problemler (1)

Problem 1. Ne yazdırır?

class Sayac {
  static int toplam = 0;
  int adet = 0;
  void arttir() { toplam++; adet++; }
}
public class Problem1 {
  public static void main(String[] args) {
    Sayac a = new Sayac(), b = new Sayac();
    a.arttir(); a.arttir(); b.arttir();
    System.out.print(a.adet + " " + b.adet);
    System.out.println(" " + Sayac.toplam);
  }
}

Problem 2. Ne yazdırır?

class Kutu { int deger; }
public class Problem2 {
  public static void main(String[] args) {
    Kutu k1 = new Kutu();
    k1.deger = 5;
    Kutu k2 = k1;
    k2.deger = 9;
    Kutu k3 = new Kutu();
    k3.deger = 9;
    System.out.println(k1.deger);
    System.out.println(k1 == k2);
    System.out.println(k2 == k3);
  }
}
Cevapları göster
  1. 2 1 3. adet her nesnede ayrıdır (a: 2, b: 1); toplam static olduğu için üç çağrının hepsini sayar: 3.
  2. 9, true, false. k2 = k1 aynı nesneyi gösterir: k2.deger = 9 sonrası k1.deger da 9. k3 ayrı nesnedir; değerleri eşit olsa da == false.

Özet

Örnek Problemler (2)

Problem 3. Ne yazdırır?

class A {
  static { System.out.print("S"); }
  { System.out.print("I"); }
  A() { System.out.print("C"); }
}
public class Problem3 {
  public static void main(String[] args) {
    System.out.print("M");
    new A();
    new A();
    System.out.println();
  }
}

Problem 4. Ne yazdırır?

class Kutu { int deger; }
public class Problem4 {
  static void degistir(Kutu k) {
    k.deger = 100;
    k = new Kutu();
    k.deger = 7;
  }
  public static void main(String[] args) {
    Kutu x = new Kutu();
    x.deger = 1;
    degistir(x);
    System.out.println(x.deger);
  }
}
Cevapları göster
  1. MSICIC. Önce main "M" yazar. A sınıfı ilk new A()'da yüklenir: static blok bir kez (S); sonra her nesne için örnek ilklendirici (I) ve yapıcı (C).
  2. 100. degistir, referansın kopyasını alır: k.deger = 100 asıl nesneyi değiştirir; k = new Kutu() yalnızca yerel kopyayı başka bir nesneye yöneltir, x etkilenmez.

Özet

Örnek Problemler (3)

Problem 5. Ne yazdırır?

record Para(int lira) { }
public class Problem5 {
  public static void main(String[] args) {
    Para p1 = new Para(10);
    Para p2 = new Para(10);
    Integer i1 = 1000, i2 = 1000;
    System.out.println(p1.equals(p2));
    System.out.println(p1 == p2);
    System.out.println(i1.equals(i2));
    System.out.println(p1);
  }
}

Problem 6. Ne yazdırır?

class Nokta {
  int x, y;
  Nokta(int x, int y) {
    this.x = x;
    this.y = y;
  }
}
public class Problem6 {
  public static void main(String[] args) {
    Nokta a = new Nokta(1, 2);
    Nokta b = new Nokta(1, 2);
    System.out.println(a.equals(b));
    System.out.println(a.x == b.x);
  }
}
Cevapları göster
  1. true / false / true / Para[lira=10]. Record'ın equals'ı içeriği, == referansı karşılaştırır; Integer için equals her zaman güvenlidir.
  2. false / true. equals yazılmamış: Object'inki referans karşılaştırır. a.x == b.x iki int değerdir.

Özet

Alıştırmalar

  1. Kitap sınıfı: private baslik, yazar, sayfaSayisi; üç parametreli yapıcı, get metotları ve toString().
  2. Kitap'a static toplamKitapSayisi sayacı ve yalnızca pozitif değeri kabul eden setSayfaSayisi ekleyin.
  3. Daire sınıfı: yaricap, alan(), cevre(). new Daire(3) için iki basamakla yazdırın.
  4. Mevsim enum'unun değerlerini sıra numaralarıyla yazdırın.
  5. OgrenciKaydi(String ad, int numara) record'unu yazıp bir nesnesini yazdırın.
Cevaplar / ipuçları
  1. this.baslik = baslik; ...; toString() → Nutuk (Atatürk, 600 s.)
  2. Yapıcıda toplamKitapSayisi++;, setter'da if (sayfaSayisi > 0) .... −5 sayfalı ikinci kitapta sayfa 0 kalır, sayaç 2: 0 2
  3. Math.PI * yaricap * yaricap, 2 * Math.PI * yaricap; printf("%.2f %.2f%n", ...) → 28,27 18,85 (Türkçe yerel ayarda virgül).
  4. for (Mevsim m : Mevsim.values()) → 0:ILKBAHAR 1:YAZ 2:SONBAHAR 3:KIS
  5. record OgrenciKaydi(String ad, int numara) { } → OgrenciKaydi[ad=Ali, numara=7]

Özet

Kaynaklar

  • Oracle, The Java Tutorials: "Classes and Objects", "Nested Classes", "Enum Types", "Record Classes", "Autoboxing and Unboxing".
  • J. Gosling ve diğ., The Java Language Specification, Java SE 21 Edition (Bölüm 8 Classes: 8.3 Fields, 8.6–8.7 Initializers, 8.8 Constructors, 8.9 Enum, 8.10 Record).
  • 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.
  • C. S. Horstmann, Core Java, Volume I: Fundamentals, 12. baskı, 2022 (Bölüm 4: Objects and Classes).
  • A. B. Downey ve C. Mayfield, Think Java, 2. baskı, O'Reilly, 2019 (Bölüm 10–11).
  • J. Bloch, Effective Java, 3. baskı, Addison-Wesley, 2018 (equals, hashCode, toString maddeleri).

Son

Bölüm 4.1: Nesneler ve Sınıflar
Sonraki bölüm: Bölüm 4.2: Sarmalama · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.