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
totaldi dalam loop tetap dapat dibaca. - Variabel yang dideklarasikan di dalam blok bersarang tidak terlihat dari luar blok tersebut — loop dan blok
ifpunya 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:
total = 14
total melampaui 5
putaran ke-0
putaran ke-1Mari kita bedah baris-baris kuncinya:
- Baris 3 (
int total = 0;): variabel tingkat method. Seluruh blok di bawahnya — kedua loop dan blokif— berada di dalam wilayahtotal, sehinggatotal += kuadrat;sah. - Baris 5-7 (
int idanint kuadrat):idideklarasikan di header loop sehingga wilayahnya persis badan loop;kuadratdideklarasikan di badan loop sehingga lahir dan mati pada setiap iterasi — tiga iterasi menciptakan tiga “kehidupan”kuadratyang berbeda. Setelah loop selesai, namaidankuadrattidak lagi dikenal. - Baris 11-14 (
String pesan): variabel berscope blokif. Baris 13 dapat membacanya karena masih di dalam kurawal; begitu}di baris 14 ditutup,pesanberhenti eksis. - Baris 16-18 (
int ikedua):idari loop pertama sudah mati, sehingga mendeklarasikanibaru di loop berikutnya sah sepenuhnya — bukan deklarasi ganda, karena keduaitidak 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:
parameter : Siti
field : Budi
field setelah diubah: SitiProgram 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:
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 berkasclass 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 berkaspublic 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 berkaspublic 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);
}
}
}