---
title: 'Değer ve Referans Aktarımı'
source: 'https://academia.sh/tr/kurslar/java-temelleri/deger-ve-referans-aktarimi'
course: 'Java Temelleri'
language: tr
updated: '2026-08-17T18:09:40+00:00'
license: 'CC BY-SA 4.0'
---

# Değer ve Referans Aktarımı

Java'nın tek bir aktarım modeli vardır ve sınıf dosyası bunu yazar: beş ayrı tipteki beş argüman aynı biçimde yüklenir, parametrenin alanına yazmak çağırana görünür, parametreyi yeniden bağlamak görünmez, ve değiştirilemez bir tipte iki durum ayırt edilemez.

Önceki ders bir dizginin `==` ile aynı, `equals` ile eşit çıkabildiğini ölçtü; iki ad bazen
tek bir nesneyi tutuyordu. Aynı soru bir çağrının sınırında da sorulabilir.

Değerle ve referansla aktarım Programlama Temelleri kursunda kavram olarak kuruldu ve
burada tekrarlanmıyor. Buradaki soru şudur: Java bu kavramların hangisini gerçekleştirir,
ve bunu sınıf dosyasından nasıl okuruz? Kaynağa bakan biri bir kaydı yönteme verdiğinde
nesnenin mi yoksa ona giden referansın mu geçtiğini göremez; sınıf dosyası görür.

## Argümanlar Tek Bir Biçimde Yüklenir

- **SD35** — Ölçülen kaynak dersin içinde yazılır; sınıf dosyasında bulunan her fazlalık
  derleyicinin eklediğidir.
- **SD36** — `Olcek` çekirdeğinin bu derste kullanılan iki ölçümü yazılır: yöntem başına
  komut sayısı ile eklenen adım, ve bir yöntemin komut adları dizisi.
- **SD37** — Çağrı ölçümündeki beş parametrenin tipleri bilerek ayrıdır: iki ilkel tip
  (biri iki yuva kaplar), bir sınıf, bir dizi ve değiştirilemez bir sınıf.

```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) {}

    static ClassModel derle(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);
        return ClassFile.of().parse(d.resolve(sinif + ".class"));
    }

    static List<Yontem> oku(String kaynak, String sinif) throws Exception {
        List<Yontem> yontemler = new ArrayList<>();
        for (MethodModel m : derle(kaynak, sinif).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));
        }
        return yontemler;
    }

    static List<String> komutlar(String kaynak, String sinif, String yontem) throws Exception {
        List<String> adlar = new ArrayList<>();
        for (MethodModel m : derle(kaynak, sinif).methods())
            if (m.methodName().stringValue().equals(yontem))
                for (CodeElement e : m.code().orElseThrow())
                    if (e instanceof Instruction i)
                        adlar.add(i.opcode().name().toLowerCase(Locale.ROOT));
        return adlar;
    }

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

```java
// Aktarim.java — argüman yükleme ve parametreye yazma sınıf dosyasında
public class Aktarim {
    static final String K = """
        class AktarimOrnek {
            static class Kayit { String ad; int adet; long agirlik; }
            static void sayiAl(int adet) {}
            static void agirlikAl(long agirlik) {}
            static void kayitAl(Kayit k) {}
            static void diziAl(int[] d) {}
            static void metinAl(String s) {}
            static void cagir(int adet, long agirlik, Kayit k, int[] d, String s) {
                sayiAl(adet); agirlikAl(agirlik); kayitAl(k); diziAl(d); metinAl(s);
            }
            static void alaniDegistir(Kayit k) { k.adet = 99; }
            static void yenidenBagla(Kayit k) { k = new Kayit(); k.adet = 99; }
            static void sayiyiArtir(int adet) { adet = adet + 1; }
            static void metniUzat(String s) { s = s + " x"; }
        }
        """;

    public static void main(String[] args) throws Exception {
        System.out.println("cagir: " + Olcek.komutlar(K, "AktarimOrnek", "cagir"));
        System.out.println();
        System.out.printf("%-14s %6s  %s%n", "yontem", "komut", "kaynakta yazilmayan adim");
        for (Olcek.Yontem y : Olcek.oku(K, "AktarimOrnek"))
            if (y.ad().endsWith("Degistir") || y.ad().endsWith("Bagla")
                    || y.ad().endsWith("Artir") || y.ad().endsWith("Uzat"))
                System.out.printf("%-14s %6d  %s%n", y.ad(), y.komut(),
                        y.eklenen().isEmpty() ? "-" : String.join(", ", y.eklenen()));
        for (String y : new String[] {"alaniDegistir", "yenidenBagla"})
            System.out.printf("%-14s %s%n", y, Olcek.komutlar(K, "AktarimOrnek", y));
    }
}
```

```
cagir: [iload_0, invokestatic, lload_1, invokestatic, aload_3, invokestatic, aload, invokestatic, aload, invokestatic, return]

yontem          komut  kaynakta yazilmayan adim
alaniDegistir       4  -
yenidenBagla        8  yeni AktarimOrnek$Kayit, AktarimOrnek$Kayit.<init>
sayiyiArtir         5  -
metniUzat           4  dinamik:makeConcatWithConstants
alaniDegistir  [aload_0, bipush, putfield, return]
yenidenBagla   [new, dup, invokespecial, astore_0, aload_0, bipush, putfield, return]
```

İlk satır kursun bu derse ait tezidir. Beş ayrı tipte beş argüman geçiyor ve sınıf
dosyasında **beş yükleme komutu** var: `iload`, `lload` ve üç `aload`. Hepsi aynı işi
yapıyor — bir yerel değişken yuvasındaki değeri yığıta koyuyor — ve aralarındaki tek fark
değerin genişliği. Tam sayı bir yuva, uzun tam sayı iki yuva kaplar; bu yüzden üçüncü
argüman `aload_3` ile yükleniyor, ikinci argüman iki numarayı birden almıştır.

Burada olmayan şey, olandan daha çok konuşuyor. Nesneyi kopyalayan bir komut yok. Bir
referansı adresiyle geçiren ayrı bir komut yok. Sınıf dosyasında "değerle geçir" ve
"referansla geçir" diye iki ayrı yol bulunmuyor; **tek** yol var ve o yol yuvadaki değeri
kopyalayıp yığıta koymaktır. Kayıt, dizi ve dizgi için yuvada duran değer bir **referanstır**;
kopyalanan şey nesne değil, o referanstır. Java'nın aktarım modeli bu tek cümledir ve
ölçümün geri kalanı bu cümlenin sonuçlarıdır.

Alt tablo iki sonucu ayırıyor. `alaniDegistir` **4** komuttur ve hiçbir adım eklenmez:
referansı yükle, değeri yükle, alana yaz. Yazma `putfield` ile **nesnenin içine** gider.
`yenidenBagla` ise **8** komuttur ve iki adım ekler: bir nesne üretimi ve bir yapıcı
çağrısı. Komut dizisi devamını yazıyor — `astore_0`, yani yeni referans **yuvanın üstüne**
yazılır. Yuva çağrılan yöntemin kendi yuvasıdır; çağıranın yuvasıyla arasında hiçbir bağ
yoktur.

Son iki satır aynı ayrımın ilkel tipteki ve dizgideki karşılığıdır: `sayiyiArtir` yuvaya
yazar, `metniUzat` bir dinamik çağrıyla yeni dizgi kurup yine yuvaya yazar.

## Görünen Değişiklik ile Görünmeyen

- **SD38** — Görünürlük ölçümünde hiçbir kimlik sayısı basılmaz; kimlik yalnız `==` ile
  sorulur.
- **SD39** — Her ölçümden önce alan bilinen bir değere kurulur; böylece değişen ile
  değişmeyen ayrılabilir.
- **SD40** — Değiştirilemez tip ölçümünde ilkel tiple dizgi **aynı** biçimde denenir. İkisi
  için de yalnız yeniden bağlama yazılabilir, çünkü dizgide yazılabilir bir üye yoktur.

```java
// Gorunur.java — hangi değişiklik çağırana görünüyor
class Kayit {
    String ad;
    int adet;
    long agirlik;
}

public class Gorunur {
    static boolean ayniNesneMi(Kayit gelen, Kayit disaridaki) { return gelen == disaridaki; }
    static void alaniDegistir(Kayit k) { k.adet = 99; }
    static void yenidenBagla(Kayit k) { k = new Kayit(); k.adet = 99; }
    static void takas(Kayit a, Kayit b) { Kayit g = a; a = b; b = g; }
    static void diziyeYaz(int[] d) { d[0] = 99; }
    static void sayiyiArtir(int adet) { adet = adet + 1; }
    static void metniUzat(String s) { s = s + " x"; }

    public static void main(String[] args) {
        Kayit k = new Kayit();
        k.ad = "kuzey";
        k.adet = 12;
        System.out.println("parametre disaridakiyle ayni nesne mi: " + ayniNesneMi(k, k));

        alaniDegistir(k);
        System.out.println("alaniDegistir sonrasi adet : " + k.adet);
        k.adet = 12;
        yenidenBagla(k);
        System.out.println("yenidenBagla sonrasi adet  : " + k.adet);

        Kayit a = new Kayit();
        a.ad = "kuzey";
        Kayit b = new Kayit();
        b.ad = "guney";
        takas(a, b);
        System.out.println("takas sonrasi a.ad, b.ad   : " + a.ad + " " + b.ad);

        int[] d = {12, 18};
        diziyeYaz(d);
        System.out.println("diziyeYaz sonrasi d[0]     : " + d[0]);

        int adet = 12;
        sayiyiArtir(adet);
        String metin = "kuzey";
        metniUzat(metin);
        System.out.println("sayi ve metin sonrasi      : " + adet + " " + metin);
    }
}
```

```
parametre disaridakiyle ayni nesne mi: true
alaniDegistir sonrasi adet : 99
yenidenBagla sonrasi adet  : 12
takas sonrasi a.ad, b.ad   : kuzey guney
diziyeYaz sonrasi d[0]     : 99
sayi ve metin sonrasi      : 12 kuzey
```

İlk satır önceki bölümün cümlesini çalışma zamanında doğruluyor: parametredeki referans ile
dışarıdaki referans **aynı nesneyi** gösteriyor. Nesne kopyalanmadı. Bu yüzden ikinci satır
şaşırtıcı değil — alana yazmak çağırana görünüyor, `adet` **99** oldu.

Üçüncü satır ayrımı koyuyor. `yenidenBagla` da alana **99** yazıyor, ama önce parametreyi
yeni bir nesneye bağladığı için yazdığı yer başka bir nesnedir; çağıranın kaydı **12**
kalıyor. Farkı yapan şey yazmanın kendisi değil, **hangi nesneye** yazıldığıdır. Dördüncü
satır bunun en bilinen biçimidir: iki parametreyi takas eden yöntem çağırana hiçbir şey
yapmaz, çünkü takas ettiği şey iki yuvadır.

Beşinci satır kuralın diziye uygulanışıdır: dizi de bir nesnedir, parametredeki referans
aynı diziyi gösterir ve `d[0] = 99` yazması çağırana görünür.

Buradan uygulanabilir bir kural çıkar. Bir yöntemin çağırana görünen etkisi ancak
**erişilebilir bir nesnenin içine yazdığında** doğar; parametreye yapılan atama hiçbir
zaman görünmez. Çağıranın verdiği nesnenin değişmesini istemiyorsak, ya nesnenin
değiştirilebilir bir üyesi olmamalı ya da yöntem kendi kopyasını kurmalıdır.

## Değiştirilemez Tipte Ayrım Gözlenmez

Son satır dersin sınırlayıcı ölçümüdür ve iki değeri yan yana koyar: sayı **12**, metin
**kuzey**. İkisi de değişmedi.

Sayının değişmemesi beklenendir; `adet` bir ilkel tiptir ve yuvada duran değer sayının
kendisidir. Asıl sonuç metindedir. `metniUzat` bir referans aldı, o referansın gösterdiği
nesne çağıranınkiyle aynıydı, ve çağıran yine hiçbir değişiklik görmedi. Yanıtı önceki
ders ölçtü: dizgide yazılabilir bir üye yoktur. `s = s + " x"` satırı nesnenin içine
yazmaz, yazamaz; yeni bir dizgi kurup parametrenin yuvasına koyar.

Bunun ölçüm açısından anlamı şudur: **değiştirilemez bir tiple bu dersin sorusu
sorulamaz.** Dizgi parametresi bir ilkel tip parametresinden ayırt edilemez, dolayısıyla
dizgiye bakarak Java'nın hangi modeli kullandığına karar verilemez. Ayrımı gözlenebilir
kılan şey aktarım biçimi değil, **nesnenin değiştirilebilir bir üyesi olmasıdır**.

## Özet

- Sınıf dosyasında argüman geçirmenin tek bir biçimi vardır: yuvadaki değeri yığıta koymak.
  Beş ayrı tipteki beş argüman beş yükleme komutuyla geçer; tek fark, değerin kapladığı
  yuva sayısıdır.
- Referans tiplerinde yuvada duran değer bir referanstır; kopyalanan şey nesne değil o
  referanstır, ve parametre ile dışarıdaki ad aynı nesneyi gösterir.
- Parametrenin alanına yazmak `putfield` ile nesnenin içine gider ve çağırana **görünür**;
  parametreyi yeniden bağlamak `astore` ile yöntemin kendi yuvasına yazar ve **görünmez**.
- İki parametreyi takas eden yöntem çağırana hiçbir şey yapmaz; dizinin bir öğesine yazan
  yöntemin etkisi ise görünür, çünkü dizi de bir nesnedir.
- Değiştirilemez bir tipte ayrım gözlenmez: dizgi parametresi ilkel tip parametresinden
  ayırt edilemez, çünkü nesnenin içine yazılacak bir üye yoktur.

## Kurs Kapanışı

Kurs tek bir soruyla açıldı: yazılan satır, sınıf dosyasında kaç adıma ve hangi adımlara
dönüşüyor? On ders bu soruyu on ayrı biçime sordu ve yanıtı her seferinde çalıştırılmış bir
ölçümden aldı. Toplandığında tek bir kural çıkıyor: **Java'da sözdizim bir kısaltmadır.**
Kaynak, sınıf dosyasına konan adımların tamamını göstermez; gösterdiği şey, o adımların
hangi biçimde isteneceğidir.

| Ders | Ölçülen biçim | Eklenen adım | Sınırlayıcı ölçüm |
|---|---|---|---|
| Kaynak, Bayt Kodu ve Sanal Makine | kaynak metni ile sınıf dosyasının karşılaştırılması | 12 yöntemin 8'inde, toplam 13 adım | kaynakta duran birleştirme dosyada hiç yok |
| Program Yaşam Döngüsü | giriş noktası ve başlatma sırası | üye eklenir: varsayılan yapıcı, 3 alan ve 5 yöntem | yapıcı yazılınca eklenen yapıcı kaybolur |
| Paketler ve İçe Aktarım | içe aktarım ile tam nitelikli ad | sıfır adım: iki dosya bayt bayt aynı | paket adı dosyayı beş bayt büyütür |
| İlkel Tipler ve Sarmalayıcılar | ilkel tip ile sarmalayıcı arasındaki geçiş | `Integer.valueOf` ve `Integer.intValue` | önbellek aralığında `==` doğru, dışında yanlış |
| Değişkenler ve Kapsam | bildirimin bulunduğu yer | alan komutları ya da yalnız bir yuva | blok kapsamı aynı 20 komutu, bir eksik yuvayla üretir |
| İşleçler ve İfadeler | sayısal yükseltme ve bileşik atama | `i2l` ve `i2b` çevirmeleri, kısa devrede dal | iki sabitte hiçbir adım eklenmez |
| Denetim Akışı | seçim ve döngü biçimleri | seçimde iki ayrı arama komutu; gelişmiş `for` listede 5 adım | aynı döngü dizide 24 komut ve sıfır adım üretir |
| Diziler | dizi üretimi, uzunluk ve erişim | dizi üretimi; `arraylength`; öğe başına yazma | kovaryansın tip denetimi komut sayısında görünmez |
| Dizgiler | birleştirme, havuz ve biriktirici | dinamik çağrı; biriktiricide üretim ve üç çağrı | iki sabitin birleştirilmesi 2 komut, sıfır adım |
| Değer ve Referans Aktarımı | argüman yükleme ve parametreye yazma | yeniden bağlamada üretim ve yuvaya yazma | değiştirilemez tipte ilkel tiple ayrım gözlenmez |

Tablonun son sütunu kursun yöntemidir. Her ders eklenen adımın **olmadığı** ya da
**kaybolduğu** bir durumu da ölçtü, çünkü her yerde bulunan bir şey hiçbir şeyi açıklamaz.
Sabit katlama, yazılmış bir yapıcı, önbellek aralığı, ilkel tipli dizi — her biri kuralın
sınırını çiziyor. Kursun ikinci okuması da buradan gelir: komut sayısı ile eklenen adım
aynı yöne gitmez, ve daha az komut daha az iş demek değildir.

Bu kursta sınıf yalnız bir kap olarak kullanıldı. Oysa ölçümler boyunca sınıfın kendisi de
sorular üretti: kaynakta yazılmayan bir yapıcı, kaynakta yazılmayan üç alan ve beş yöntem,
bir kaydın alanına yazıldığında çağırana görünen değişiklik. Sıradaki kurs olan **Nesneye
Dayalı Java** sınıfı kap olmaktan çıkarıp konu yapar. Aynı ölçü orada da işini görecek —
bir çağrının hangi yönteme gittiğine kimin ve ne zaman karar verdiği yine sınıf
dosyasından okunabilir.
