---
title: Dizgiler
source: 'https://academia.sh/tr/kurslar/java-temelleri/dizgiler'
course: 'Java Temelleri'
language: tr
updated: '2026-08-17T18:09:40+00:00'
license: 'CC BY-SA 4.0'
---

# Dizgiler

Aynı `+` işleci dizgide iki ayrı sonuç verir: iki sabit arasında sınıf dosyasında hiçbir iz bırakmaz, değişkenler arasında bir dinamik çağrıya dönüşür; döngüde ise 24 komutluk yazım 20 dizgi nesnesi bırakırken 27 komutluk biriktirici tek bir nesne üretir.

Önceki ders `String[]` dizisine yazmanın çalışma zamanında denetlendiğini ölçtü; yazılan
değer her seferinde hazır bir dizgi nesnesiydi. Bu ders o nesneye bakar.

Dizginin değiştirilemez olduğu Programlama Temelleri kursunda kuruldu ve burada
tekrarlanmıyor. Buradaki soru şudur: değiştirilemezlik ne kadar tutuyor? Kaynakta yazılan
`+` işleci sınıf dosyasında hangi adıma dönüşür, aynı sabiti iki kez yazmak kaç nesne
üretir, ve bir döngü içinde büyütülen metin yol boyunca kaç nesne bırakır?

## Birleştirme İşleci Sınıf Dosyasında Kalmaz

- **SD28** — Ölçülen kaynak metni dersin içinde yazılır; sınıf dosyasında bulunan her
  fazlalık derleyicinin eklediğidir.
- **SD29** — `Olcek` çekirdeği ortak tanımdan gelir. Bu ders onun yalnız kullandığı üç
  kaydını yazar: çağrı, dinamik çağrı ve nesne üretimi. Ölçümlerin davranışı değişmez.
- **SD30** — Ölçülen altı yöntemin dördü birleştirmenin dört ayrı biçimidir: iki sabit
  arasında, bir değişkenle, üç işleçle ve bir döngü boyunca. Kalan ikisi karşılaştırma
  içindir.

```java
// Olcek.java — ortak ölçüm çekirdeği: derleyicinin sınıf dosyasına ne koyduğunu okur
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.classfile.*;
import java.lang.classfile.instruction.*;
import java.nio.file.*;
import java.util.*;
import java.util.spi.ToolProvider;

class Olcek {
    record Yontem(String ad, int komut, List<String> eklenen) {}
    record Sinif(List<Yontem> yontem, List<String> alan) {}

    static Sinif oku(String kaynak, String sinif) throws Exception {
        Path d = Files.createTempDirectory("olcek");
        Path k = d.resolve(sinif + ".java");
        Files.writeString(k, kaynak);
        PrintWriter bos = new PrintWriter(Writer.nullWriter());
        if (ToolProvider.findFirst("javac").orElseThrow()
                .run(bos, bos, "-d", d.toString(), k.toString()) != 0)
            throw new IllegalStateException("derlenmedi: " + sinif);
        ClassModel cm = ClassFile.of().parse(d.resolve(sinif + ".class"));
        List<Yontem> yontemler = new ArrayList<>();
        for (MethodModel m : cm.methods()) {
            if (m.code().isEmpty()) continue;
            List<String> eklenen = new ArrayList<>();
            int komut = 0;
            for (CodeElement e : m.code().get()) {
                if (e instanceof Instruction) komut++;
                if (e instanceof InvokeInstruction iv)
                    eklenen.add(kisa(iv.owner().asInternalName()) + "." + iv.name().stringValue());
                else if (e instanceof InvokeDynamicInstruction id)
                    eklenen.add("dinamik:" + id.name().stringValue());
                else if (e instanceof NewObjectInstruction n)
                    eklenen.add("yeni " + kisa(n.className().asInternalName()));
            }
            yontemler.add(new Yontem(m.methodName().stringValue(), komut, eklenen));
        }
        List<String> alanlar = new ArrayList<>();
        for (FieldModel f : cm.fields()) alanlar.add(f.fieldName().stringValue());
        return new Sinif(yontemler, alanlar);
    }

    static String kisa(String ic) { return ic.substring(ic.lastIndexOf('/') + 1); }
}
```

```java
// Birlestirme.java — dizgi birleştirme sınıf dosyasında neye dönüşüyor
public class Birlestirme {
    static final String K = """
        class DizgiOrnek {
            static String birlestir(String ad, int adet) { return ad + adet; }
            static String sabitBirlestir() { return "ba" + "sit"; }
            static int uzunluk(String s) { return s.length(); }
            static String satir(String ad, int adet, long agirlik) {
                return ad + " x" + adet + " (" + agirlik + " g)";
            }
            static String donguyleBirlestir(String[] d) {
                String s = "";
                for (String x : d) s += x;
                return s;
            }
            static String biriktiriciyle(String[] d) {
                StringBuilder b = new StringBuilder();
                for (String x : d) b.append(x);
                return b.toString();
            }
        }
        """;

    public static void main(String[] args) throws Exception {
        System.out.printf("%-18s %6s  %s%n", "yontem", "komut", "kaynakta yazilmayan adim");
        for (Olcek.Yontem y : Olcek.oku(K, "DizgiOrnek").yontem())
            if (!y.ad().equals("<init>"))
                System.out.printf("%-18s %6d  %s%n", y.ad(), y.komut(),
                        y.eklenen().isEmpty() ? "-" : String.join(", ", y.eklenen()));

        String ad = "kuzey";
        int adet = 12;
        long agirlik = 1800;
        System.out.println("\nsatir yaziminin urettigi metin: "
                + ad + " x" + adet + " (" + agirlik + " g)");
    }
}
```

```
yontem              komut  kaynakta yazilmayan adim
birlestir               4  dinamik:makeConcatWithConstants
sabitBirlestir          2  -
uzunluk                 3  String.length
satir                   5  dinamik:makeConcatWithConstants
donguyleBirlestir      24  dinamik:makeConcatWithConstants
biriktiriciyle         27  yeni StringBuilder, StringBuilder.<init>, StringBuilder.append, StringBuilder.toString

satir yaziminin urettigi metin: kuzey x12 (1800 g)
```

Birinci satır dersin ana ölçümüdür. Kaynakta `ad + adet` yazılıdır ve orada bir işleç
durur; sınıf dosyasında ise bir **dinamik çağrı** vardır. Dizgi birleştirme, sınıf
dosyasında bir işleç olarak bulunmaz — çünkü karşılığı olan bir birleştirme komutu yoktur.
Derleyici işleci bir çağrıya çevirir; çağrının nasıl gerçekleştirileceği çalışma zamanına
bırakılır ve sınıf dosyasında yalnız işlemin adıyla kaynakta yazılan sabit parçalar durur.
Kaynağa bakan biri bir sayının metne çevrildiğini de göremez: `adet` bir tam sayıdır ve o
çevrim de aynı çağrının içindedir.

İkinci satır aynı işleci sıfıra indiriyor. `"ba" + "sit"` yazan yöntem **2** komuttur:
sabiti yükle, döndür. Ortada birleştirme yoktur. İki dizgi sabiti derleme sırasında tek bir
sabite katlanmıştır — ilk derste ölçülen sabit katlamanın dizgideki karşılığı budur. Aynı
`+` işleci, bir satırda bir çağrı, öteki satırda hiçbir şey.

Üçüncü satır önceki dersle arasındaki farkı koyuyor. Dizide `d.length` bir komuttu; dizgide
`s.length()` bir **çağrıdır** ve ölçek onu eklenen adım olarak kaydediyor. Sözdizim de bunu
söyler: dizide ayraç yoktur, dizgide vardır. Uzunluk dizide nesnenin başlığından okunur,
dizgide ise bir yöntem çağrısıyla istenir; ikisi aynı sözcükle yazıldığı için karıştırılır,
sınıf dosyasında hiç benzemezler.

Dördüncü satır işlecin en çok kullanılan biçimini ölçüyor. Kayıt satırını kuran `satir`
yönteminde **üç** `+` işleci var, ama sınıf dosyasında **tek bir** dinamik çağrı duruyor ve
yöntemin tamamı **5** komut. Derleyici art arda gelen birleştirmeleri ayrı ayrı çevirmez;
bütün parçaları tek bir çağrıya toplar. Kaynağa bakarak "her `+` bir ara metin üretir"
demek bu yüzden yanlış olurdu — bir ifade içindeki birleştirmelerin sayısı, üretilen ara
nesnelerin sayısı değildir. Alt satır bu yazımın ürettiği metni gösteriyor: kaydın adı,
adedi ve gram cinsinden ağırlığı tek bir çağrıda birleşiyor.

Alt iki satır ikinci çifti kuruyor. Döngü içinde `s += x` yazan yöntem **24** komut,
biriktiriciyle yazılan yöntem **27** komut. Komut sayısına bakan biri birinciyi seçerdi.
Eklenen adım listesi ise ters yönü gösteriyor: birincide döngünün her turunda çalışan tek
bir dinamik çağrı var, ikincide bir nesne üretimi ve üç çağrı. Sayılar burada bir seçim
gerekçesi vermiyor; komut sayısı programın kaç kez ne yaptığını söylemez.

## Döngüde Kalan Nesneler

- **SD31** — Ölçüm süre ölçmez; **üretilen dizgi nesnesi** sayar. Her turda sonucun bir
  önceki nesneyle aynı olup olmadığı `==` ile sorulur ve ayrı çıkan sayılır. Hiçbir kimlik
  sayısı basılmaz.
- **SD32** — Parça sayısı üç ayrı değerle denenir; ölçülen şey tek bir sayı değil, sayının
  parça sayısıyla nasıl değiştiğidir.

```java
// Uretim.java — döngüde kaç dizgi nesnesi kalıyor
public class Uretim {
    static String[] parcalar(int n) {
        String[] d = new String[n];
        for (int i = 0; i < n; i++) d[i] = (i % 2 == 0) ? "kuzey" : "-";
        return d;
    }

    static int islecle(String[] d) {
        String s = "";
        int uretilen = 0;
        for (String x : d) {
            String onceki = s;
            s = s + x;
            if (s != onceki) uretilen++;
        }
        return uretilen;
    }

    static boolean biriktiriciAyni(String[] d) {
        StringBuilder b = new StringBuilder();
        boolean ayni = true;
        for (String x : d) ayni = ayni && (b.append(x) == b);
        return ayni;
    }

    public static void main(String[] args) {
        System.out.printf("%6s %22s %28s%n", "parca", "islecle uretilen dizgi",
                "append ayni nesneyi dondurdu");
        for (int n : new int[] {5, 10, 20})
            System.out.printf("%6d %22d %28s%n", n, islecle(parcalar(n)),
                    biriktiriciAyni(parcalar(n)));

        StringBuilder b = new StringBuilder();
        for (String x : parcalar(5)) b.append(x);
        System.out.println("\ntoString iki cagri ayni nesne mi: " + (b.toString() == b.toString()));
        String isleclerle = "";
        for (String x : parcalar(5)) isleclerle += x;
        System.out.println("iki yol ayni metni mi veriyor: " + isleclerle.equals(b.toString()));
        System.out.println("sonuc: " + b);
    }
}
```

```
 parca islecle uretilen dizgi append ayni nesneyi dondurdu
     5                      5                         true
    10                     10                         true
    20                     20                         true

toString iki cagri ayni nesne mi: false
iki yol ayni metni mi veriyor: true
sonuc: kuzey-kuzey-kuzey
```

Sayı parça sayısıyla birebir gidiyor: 5 parça 5 nesne, 20 parça 20 nesne. Bunların yalnız
sonuncusu kullanılır; öteki on dokuzu kurulup atılır. Bu bir gerçekleştirim ayrıntısı
değil, değiştirilemezliğin doğrudan sonucudur. `s += x` yazımı `s` nesnesine bir ek
yapamaz, çünkü dizgi üzerinde yazma diye bir işlem yoktur; yapabileceği tek şey yeni bir
dizgi kurup adı ona bağlamaktır. Önceki dersteki dizinin sabit boyutu gibi, bu da bir yasak
değil, karşılığı olan bir işlemin yokluğudur.

Buradaki `+=` yazımı da bir kısaltmadır ve kısaltmanın açılımı tipe göre değişir. Sayıda
`+=` sessiz bir daraltma çevirmesi ekler ve değeri yerinde değiştirir; dizgide bir dinamik
çağrı ekler, yeni bir nesne kurar ve adı ona **yeniden bağlar**. İki yazım aynı görünür,
iki eklenen adım ayrıdır ve ikisi de kaynakta yazılmamıştır.

Üçüncü sütun biriktiricinin neden ayrıldığını söylüyor: `append` çağrısı **çağrıldığı
nesnenin kendisini** döndürüyor, yirmi turun yirmisinde de. Biriktirici değiştirilebilir
bir tampon tutar; ekleme onun içine yazılır ve yeni nesne kurulmaz. Dizgi yalnız
`toString` çağrıldığında üretilir, o çağrı da bir kez yapılır. Alt satır bu çağrının
gerçekten üretim olduğunu doğruluyor: art arda iki `toString` çağrısı **ayrı** nesneler
veriyor.

Böylece iki yolun tablosu tamamlanıyor. İşleçli yol 24 komut ve **n** nesne, biriktiricili
yol 27 komut ve **1** nesne; ikisi de aynı metni veriyor. Kursun ikinci iddiası burada tam
biçimini alıyor: komut sayısı ile yapılan iş aynı yöne gitmez. Sınıf dosyasındaki komut
sayısı bir yöntemin **ne kadar yazıldığını** ölçer, kaç kez çalıştığını değil. Döngü
içindeki tek bir komut, döngü dışındaki üç komuttan daha çok iş yapar.

Buradan doğrudan bir kural çıkar ve o kural yazıma bakılarak uygulanabilir: birleştirme
sayısı **derleme zamanında belliyse** işleç yeterlidir, çünkü tek çağrıya derlenir; sayı
çalışma zamanında belirleniyorsa biriktirici kullanılır.

## Sabit Üretilmez, Havuzdan Alınır

- **SD33** — Kimlik ölçümünde yalnız `==` ve `equals` sonuçları basılır; hiçbir kimlik
  değeri ya da adres yazılmaz.
- **SD34** — Karşılaştırılan beş dizginin beşi de aynı harfleri taşır; ölçülen tek şey
  bunların **aynı nesne** olup olmadığıdır.

```java
// Havuz.java — dizgi sabiti üretilmez, havuzdan alınır
public class Havuz {
    static final String K = """
        class HavuzOrnek {
            static String bir() { return "kuzey"; }
            static String iki() { return "kuzey"; }
            static String uretilmis() { return new String("kuzey"); }
        }
        """;

    static void yaz(String ad, String a, String b) {
        System.out.printf("%-32s %7s %8s%n", ad, a == b, a.equals(b));
    }

    public static void main(String[] args) throws Exception {
        System.out.printf("%-14s %6s  %s%n", "yontem", "komut", "kaynakta yazilmayan adim");
        for (Olcek.Yontem y : Olcek.oku(K, "HavuzOrnek").yontem())
            if (!y.ad().equals("<init>"))
                System.out.printf("%-14s %6d  %s%n", y.ad(), y.komut(),
                        y.eklenen().isEmpty() ? "-" : String.join(", ", y.eklenen()));

        String sabit = "kuzey";
        String ikinci = "kuzey";
        String sabitToplam = "kuz" + "ey";
        String hesaplanan = "kuz" + sabit.substring(3);
        String uretilmis = new String("kuzey");

        System.out.printf("%n%-32s %7s %8s%n", "\"kuzey\" ile karsilastirilan", "==", "equals");
        yaz("ikinci kez yazilan sabit", ikinci, sabit);
        yaz("\"kuz\" + \"ey\"", sabitToplam, sabit);
        yaz("calisma zamaninda birlestirilen", hesaplanan, sabit);
        yaz("new String(\"kuzey\")", uretilmis, sabit);
        yaz("hesaplanan.intern()", hesaplanan.intern(), sabit);
    }
}
```

```
yontem          komut  kaynakta yazilmayan adim
bir                 2  -
iki                 2  -
uretilmis           5  yeni String, String.<init>

"kuzey" ile karsilastirilan           ==   equals
ikinci kez yazilan sabit            true     true
"kuz" + "ey"                        true     true
calisma zamaninda birlestirilen    false     true
new String("kuzey")                false     true
hesaplanan.intern()                 true     true
```

Üst tablo dersin sınırlayıcı ölçümüdür. Bir dizgi sabiti döndüren yöntem **2** komuttur ve
eklenen adım sütunu boştur: hiçbir üretim, hiçbir çağrı, hiçbir çevirme yok. Sabit sınıf
dosyasında hazır durur ve çalışma zamanında **üretilmez**, yalnız yüklenir. Aynı sabiti
ikinci kez yazmak da ikinci bir nesne kurmaz. Buna karşılık `new String("kuzey")` yazımı
**5** komuttur ve iki adım ekler: bir nesne üretimi ve bir yapıcı çağrısı. Kaynakta yazılan
tek fark bir anahtar sözcüktür; sınıf dosyasındaki fark üç komut ve bir nesnedir.

Alt tablo bunun kimlik üzerindeki sonucunu veriyor. İki kez yazılan sabit **aynı**
nesnedir; iki sabitin birleştirilmesi de aynı nesnedir, çünkü o birleştirme derleme
zamanında yapılmış ve sonuç yine bir sabit olmuştur. Aynı harfler çalışma zamanında
birleştirildiğinde ise sonuç **ayrı** bir nesnedir, ve `new String` her çağrıda ayrı bir
nesne verir. Beş satırın beşinde de `equals` doğru: içerik hep aynı, kimlik değil.

Bunları toplayan yer **dizgi havuzudur**: sabitler tek bir havuzda tutulur ve aynı harf
dizisi bir kez saklanır. Son satır havuza sonradan girmenin yolunu gösteriyor — `intern`
çağrısı, çalışma zamanında kurulmuş bir dizginin havuzdaki karşılığını verir ve sonuç
sabitle aynı nesne çıkar. Bunun tek pratik sonucu şudur: dizgiler `==` ile
karşılaştırılmaz. İşleç bazen doğru yanıt verir, ve tam da bu yüzden güvenilmezdir; doğru
yanıtı veren şey içerik değil, sabitin nereden geldiğidir.

`intern` çağrısı bu tabloyu düzeltmenin yolu gibi görünebilir, ama düzelttiği şey ölçümün
kendisi değildir: havuza her giriş bir arama ve bir saklama ister, ve bu ders o adımları
saymadı. Karşılaştırma için `equals` kullanmak hem daha az varsayım hem daha az adım
gerektirir; `intern` yalnız aynı metnin çok kez tutulduğu ve tek bir kopyada toplanmasının
istendiği durumda ölçülecek bir seçenektir.

## Özet

- Dizgi birleştirme sınıf dosyasında bir işleç değildir: değişkenler arasındaki `+` bir
  dinamik çağrıya dönüşür, sayıdan metne çevrim de o çağrının içindedir, ve bir ifadedeki
  üç işleç yine **tek** çağrı verir.
- Dizide `d.length` bir komuttur, dizgide `s.length()` bir çağrıdır; aynı sözcük iki tipte
  ayrı adımlara derlenir.
- İki dizgi sabitinin birleştirilmesi **hiçbir** adım eklemez: yöntem 2 komuttur, sabit
  derleme zamanında katlanmıştır.
- Döngüde `+=` ile büyütülen metin parça başına bir dizgi bırakır — 20 parça 20 nesne —
  çünkü dizgi üzerinde yazma diye bir işlem yoktur; biriktiricide ise `append` çağrıldığı
  nesnenin kendisini döndürür ve dizgi yalnız `toString` ile bir kez üretilir.
- İşleçli yol **24**, biriktiricili yol **27** komuttur: daha az komut daha az iş demek
  değildir, çünkü komut sayısı kaç kez çalıştığını söylemez.
- Aynı harfleri taşıyan beş dizginin üçü sabitle aynı nesne, ikisi ayrıdır; `equals`
  beşinde de doğrudur, bu yüzden dizgiler `==` ile karşılaştırılmaz.

## Sonraki Adım

Bu derste bir dizginin `==` ile aynı, `equals` ile eşit çıkabildiği ölçüldü; iki ad bazen
tek bir nesneyi tuttu. Aynı soru bir yöntem çağrısında da sorulabilir: bir kayıt nesnesi
bir yönteme verildiğinde çağrılan yöntem hangi şeye erişir, ve o nesnenin alanını
değiştirmekle parametreyi yeniden bağlamak neden ayrı sonuçlar verir? Sıradaki ders
Java'nın tek aktarım modelini sınıf dosyasından okur ve kursu kapatır.
