Deklarasi variabel bukan sekadar menciptakan nama — deklarasi juga menetapkan wilayah kode tempat nama tersebut dikenal (scope) dan berapa lama memori variabel itu bertahan (lifetime). Variabel yang dideklarasikan di dalam blok if tidak dapat dibaca setelah blok berakhir; variabel loop mati begitu loop selesai; field hidup selama objeknya hidup. Pemahaman scope mencegah sekumpulan error compiler yang membingungkan pemula dan — lebih penting lagi — melatih kita merancang variabel yang hidupnya sekecil mungkin. Chapter ini menutup Section Variabel dan Tipe Data dengan peta lengkap ruang lingkup variabel Java.

Scope Ditentukan oleh Kurung Kurawal #

Aturan dasarnya satu kalimat: variabel dikenal mulai dari deklarasinya hingga kurung kurawal penutup blok tempat variabel dideklarasikan. Blok dimulai { dan berakhir } — milik method, blok if, loop, atau blok mandiri. Konsekuensinya bertingkat:

  • Variabel di badan method terlihat oleh seluruh statement di dalamnya, termasuk blok-blok bersarang — itulah sebabnya total di dalam loop tetap dapat dibaca.
  • Variabel yang dideklarasikan di dalam blok bersarang tidak terlihat dari luar blok tersebut — loop dan blok if punya wilayah sendiri.
  • Dua blok yang berdampingan (saudara, bukan bersarang) masing-masing boleh memakai nama yang sama, karena wilayah keduanya tidak pernah bertumpuk.

Menelusuri Ruang Lingkup #

Program berikut menyusun ketiga aturan tersebut dalam satu alur:

public class RuangLingkup {
    public static void main(String[] args) {
        int total = 0;                    // scope: seluruh method main

        for (int i = 1; i <= 3; i++) {    // i hanya hidup di loop
            int kuadrat = i * i;          // lahir dan mati tiap iterasi
            total += kuadrat;
        }
        System.out.println("total = " + total);

        if (total > 5) {
            String pesan = "total melampaui 5";   // hanya hidup di blok if
            System.out.println(pesan);
        }

        for (int i = 0; i < 2; i++) {     // i baru di loop baru: sah
            System.out.println("putaran ke-" + i);
        }
    }
}

Output yang Dihasilkan:

text
total = 14
total melampaui 5
putaran ke-0
putaran ke-1

Mari kita bedah baris-baris kuncinya:

  1. Baris 3 (int total = 0;): variabel tingkat method. Seluruh blok di bawahnya — kedua loop dan blok if — berada di dalam wilayah total, sehingga total += kuadrat; sah.
  2. Baris 5-7 (int i dan int kuadrat): i dideklarasikan di header loop sehingga wilayahnya persis badan loop; kuadrat dideklarasikan di badan loop sehingga lahir dan mati pada setiap iterasi — tiga iterasi menciptakan tiga “kehidupan” kuadrat yang berbeda. Setelah loop selesai, nama i dan kuadrat tidak lagi dikenal.
  3. Baris 11-14 (String pesan): variabel berscope blok if. Baris 13 dapat membacanya karena masih di dalam kurawal; begitu } di baris 14 ditutup, pesan berhenti eksis.
  4. Baris 16-18 (int i kedua): i dari loop pertama sudah mati, sehingga mendeklarasikan i baru di loop berikutnya sah sepenuhnya — bukan deklarasi ganda, karena kedua i tidak pernah hidup bersamaan.

Field dan Shadowing #

Wilayah terluas dimiliki field: variabel yang dideklarasikan di badan class terlihat oleh seluruh method dan constructor class tersebut. Ketika parameter atau variabel lokal memakai nama yang sama dengan field, variabel tersebut menaungi (shadowing) field di dalam wilayahnya — nama yang polos menunjuk variabel lokal, sedangkan field harus diakses lewat this.:

class Akun {
    String pemilik = "Budi";              // field: scope seluruh class

    void setPemilik(String pemilik) {     // parameter menaungi field
        System.out.println("parameter : " + pemilik);
        System.out.println("field     : " + this.pemilik);
        this.pemilik = pemilik;
    }
}

public class BayanganField {
    public static void main(String[] args) {
        Akun akun = new Akun();
        akun.setPemilik("Siti");
        System.out.println("field setelah diubah: " + akun.pemilik);
    }
}

Output yang Dihasilkan:

text
parameter : Siti
field     : Budi
field setelah diubah: Siti

Program di atas memperlihatkan tiga wilayah yang bertumpuk. Baris System.out.println("parameter : " + pemilik); membaca parameter pemilik bernilai "Siti" karena parameter menaungi field pada seluruh badan method. Baris berikutnya memakai this.pemilik untuk menembus naungan dan membaca field yang masih "Budi". Terakhir, this.pemilik = pemilik; menyalin isi parameter ke field — pola setter standar yang kita jumpai terus-menerus di kode Java.

Sebaliknya, dua variabel lokal tidak boleh saling menaungi. Mendeklarasikan int nilai = 10; lalu int nilai = 20; di method yang sama ditolak compiler dengan pesan variable nilai is already defined in method main(String[]) — berbeda dengan kasus field, di sini kedua nama hidup di wilayah yang sama persis sehingga bentrokan tidak bisa ditoleransi.

Variabel di Luar Bloknya #

Pelanggaran scope paling klasik: memakai variabel setelah bloknya berakhir. Berkas berikut sengaja berisi kesalahan tersebut:

java DiLuarBlok.java
public class DiLuarBlok {
    public static void main(String[] args) {
        if (args.length == 0) {
            int kupon = 100;
            System.out.println("kupon di dalam blok: " + kupon);
        }
        System.out.println("kupon di luar blok: " + kupon);
    }
}

Compiler javac menolak dengan error: cannot find symbol, dengan rincian symbol: variable kupon, location: class DiLuarBlok. Pesan tersebut tampak membingungkan bagi pemula — kupon jelas ada di baris ke-4! Namun compiler benar: pada baris terakhir, blok if sudah ditutup dan variabel kupon sudah tidak dikenal. Solusinya bukan memindah kurawal, melainkan mendeklarasikan variabel di wilayah yang memang memuat seluruh pemakaiannya — dalam kasus ini, tingkat method.

Lifetime dari Deklarasi hingga Pemungutan #

Scope menjawab “di mana dikenal”; lifetime menjawab “berapa lama memori bertahan”. Untuk variabel lokal, kedua jawaban itu identik: memori dialokasikan di stack frame saat deklarasi dieksekusi dan dilepas begitu blok berakhir — variabel loop yang berjalan sepuluh juta iterasi tidak menumpuk sepuluh juta salinan, karena setiap iterasi memakai ulang slot yang sama. Untuk field, lifetime mengikuti objeknya: field lahir saat new dieksekusi, bertahan selama objek dirujuk, dan memori barunya dikembalikan kepada garbage collector setelah rujukan terakhir putus. Field static hidup paling lama — sejak class dimuat JVM hingga program berakhir.

Dengan scope dan lifetime, peta variabel Java kini lengkap: dari deklarasi, tipe primitive dan reference, konversi dan promosi, luapan dan presisi, hingga wrapper dan wilayah hidupnya. Kita sudah dapat menyimpan data dengan aman; bagian berikutnya mengajak kita mengolahnya — Section Operator membahas operator aritmetika, perbandingan, logika, hingga prioritas eksekusinya.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

BayanganField.java

Unduh berkas
java
class Akun {
    String pemilik = "Budi";              // field: scope seluruh class

    void setPemilik(String pemilik) {     // parameter menaungi field
        System.out.println("parameter : " + pemilik);
        System.out.println("field     : " + this.pemilik);
        this.pemilik = pemilik;
    }
}

public class BayanganField {
    public static void main(String[] args) {
        Akun akun = new Akun();
        akun.setPemilik("Siti");
        System.out.println("field setelah diubah: " + akun.pemilik);
    }
}

DiLuarBlok.java

Unduh berkas
java
public class DiLuarBlok {
    public static void main(String[] args) {
        if (args.length == 0) {
            int kupon = 100;
            System.out.println("kupon di dalam blok: " + kupon);
        }
        System.out.println("kupon di luar blok: " + kupon);
    }
}

RuangLingkup.java

Unduh berkas
java
public class RuangLingkup {
    public static void main(String[] args) {
        int total = 0;                    // scope: seluruh method main

        for (int i = 1; i <= 3; i++) {    // i hanya hidup di loop
            int kuadrat = i * i;          // lahir dan mati tiap iterasi
            total += kuadrat;
        }
        System.out.println("total = " + total);

        if (total > 5) {
            String pesan = "total melampaui 5";   // hanya hidup di blok if
            System.out.println(pesan);
        }

        for (int i = 0; i < 2; i++) {     // i baru di loop baru: sah
            System.out.println("putaran ke-" + i);
        }
    }
}