Setiap field yang kita buat sejauh ini punya karakter yang sama: satu salinan per object. Seratus object Anggota berarti seratus salinan field nama, masing-masing milik object-nya. Namun ada data yang secara alami bukan milik satu object, melainkan milik class itu sendiri: berapa total anggota yang sudah terdaftar, berapa kuota pinjam yang berlaku untuk semua anggota, atau method utilitas yang tidak butuh object sama sekali. Untuk kebutuhan semacam ini Java menyediakan kata kunci static. Pada Chapter ini kita buktikan lewat penghitung bahwa field static benar-benar dibagi bersama, lalu kita pelajari batas tegasnya: method static tidak boleh menyentuh member instance.
Member Milik Class, Bukan Milik Object #
Menuliskan static pada deklarasi field atau method memindahkan kepemilikan member dari object ke class. Saat JVM memuat class Anggota, field static milik class tersebut langsung diciptakan — cukup sekali — sebelum object pertama dijadikan. Object-object yang kemudian diciptakan tetap bisa membaca dan menulis field itu, tetapi mereka semua berbagi variabel yang sama; tidak ada salinan per object. Field static karenanya disebut class variable, dan konsekuensinya dua arah: nilainya bisa dibaca lewat nama class tanpa object apa pun, dan perubahan dari satu object terlihat oleh semua object lain.
Method static mengikuti logika yang sama: method tersebut melekat pada class, bisa dipanggil lewat nama class tanpa menciptakan object, dan — karena tidak berjalan “di atas” object tertentu — tidak memiliki referensi this. Dari situ mengalir larangan penting yang akan kita buktikan sebentar lagi: method static tidak dapat mengakses field atau method instance secara langsung.
Field static sebagai Penghitung Bersama #
Class Anggota berikut membawa dua member static: penghitung jumlahAnggota yang dinaikkan setiap kali constructor berjalan, dan konstanta MAKSIMUM_PINJAM. Field nomor sengaja disediakan untuk membekukan urutan pendaftaran setiap anggota:
class Anggota {
static int jumlahAnggota = 0;
static final int MAKSIMUM_PINJAM = 5;
String nama;
String kota;
int nomor;
Anggota(String nama, String kota) {
jumlahAnggota = jumlahAnggota + 1;
this.nomor = jumlahAnggota;
this.nama = nama;
this.kota = kota;
}
static int getJumlahAnggota() {
return jumlahAnggota;
}
int sisaKuotaPinjam(int sedangDipinjam) {
return MAKSIMUM_PINJAM - sedangDipinjam;
}
void tampilkanProfil() {
System.out.println("Anggota #" + nomor + ": " + nama + " dari " + kota);
}
}Program pemanggilnya mengamati penghitung dari tiga titik waktu yang berbeda, lalu mencetak profil ketiga object:
public class AplikasiAnggota {
public static void main(String[] args) {
System.out.println("Maksimum pinjam per anggota: " + Anggota.MAKSIMUM_PINJAM);
Anggota dewi = new Anggota("Dewi Lestari", "Jakarta");
System.out.println("Setelah dewi : jumlahAnggota = " + Anggota.jumlahAnggota);
Anggota budi = new Anggota("Budi Santoso", "Surabaya");
System.out.println("Setelah budi : jumlahAnggota = " + Anggota.jumlahAnggota);
Anggota siti = new Anggota("Siti Rahmawati", "Bandung");
System.out.println("Setelah siti : jumlahAnggota = " + Anggota.getJumlahAnggota());
System.out.println("--- profil ---");
dewi.tampilkanProfil();
budi.tampilkanProfil();
siti.tampilkanProfil();
}
}Output yang Dihasilkan:
Maksimum pinjam per anggota: 5
Setelah dewi : jumlahAnggota = 1
Setelah budi : jumlahAnggota = 2
Setelah siti : jumlahAnggota = 3
--- profil ---
Anggota #1: Dewi Lestari dari Jakarta
Anggota #2: Budi Santoso dari Surabaya
Anggota #3: Siti Rahmawati dari BandungOutput tersebut memuat dua bukti sekaligus. Mari kita bedah:
- Baris 3 (
Anggota.MAKSIMUM_PINJAM): konstanta diakses lewat nama class, bukan lewat object — tepat sebelum object pertama diciptakan. Akses semacam ini hanya mungkin karena memberstaticsudah hidup sejak class dimuat. - Baris 5-10 (
new Anggota(...)tiga kali): setiap constructor menjalankanjumlahAnggota = jumlahAnggota + 1, dan nilainya naik dari1ke2lalu3. Angka yang terus berlanjut itu membuktikan bahwa ketiga object menulis pada satu variabel yang sama — bukan tiga salinan terpisah yang selalu bernilai1. - Baris 12 (
Anggota.getJumlahAnggota()): methodstaticdipanggil lewat nama class tanpa bantuan object mana pun, dan mengembalikan nilai terkini penghitung bersama. - Baris 14-17 (
dewi.tampilkanProfil();dst.): setiap profil mencetaknomoryang dibekukan saat constructor berjalan. Field instancenomormenunjukkan salinan per object (#1,#2,#3), kontras yang sehat dengan penghitung bersama yang terus berubah.
Method static dan Batasnya #
Method static hidup di sisi class, sementara field instance hidup di sisi object — dan jurang itu tidak boleh diseberangi seenaknya. Method static tidak punya this, sehingga compiler tidak punya cara mengetahui object mana yang dimaksud ketika method tersebut menyebut field instance. Potongan berikut memperlihatkan pelanggarannya:
class Anggota {
String nama; // field instance
static void sapa() {
System.out.println(nama); // ditolak compiler
}
}Compiler javac menolak baris tersebut dengan pesan verbatim non-static variable nama cannot be referenced from a static context. Arah sebaliknya tidak masalah: method instance boleh leluasa membaca field dan method static — method sisaKuotaPinjam pada class Anggota kita contohnya, yang membaca konstanta MAKSIMUM_PINJAM dari dalam method instance.
Konstanta static final #
Kombinasi static final adalah pola baku untuk konstanta. Kata static memastikan satu salinan untuk seluruh class tanpa perlu object, dan kata final memastikan nilainya tidak bisa ditugaskan ulang setelah inisialisasi — upaya menulis Anggota.MAKSIMUM_PINJAM = 10; akan ditolak compiler. Konvensi penamaan konstanta memakai huruf kapital semua dengan pemisah garis bawah, sebagaimana MAKSIMUM_PINJAM pada contoh kita, sehingga pembaca kode langsung mengenali sifatnya sekali pandang.
Kata kunci static menuntaskan perjalanan kita memahami isi sebuah class yang berdiri sendiri: field, method, constructor, hingga member milik class. Namun OOP belum menyentuh janji terbesarnya — menulis kode sekali lalu memakainya berulang di banyak class. Waktunya tiba untuk pilar kedua: inheritance, dimulai dari kata kunci extends yang menghubungkan class baru ke class yang sudah ada.
Referensi #
- Java Language Specification — Chapter 8: Classes
- Oracle: dev.java — Object-Oriented Programming
- API java.base — java.lang.Object
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
Anggota.java
Unduh berkasclass Anggota {
static int jumlahAnggota = 0;
static final int MAKSIMUM_PINJAM = 5;
String nama;
String kota;
int nomor;
Anggota(String nama, String kota) {
jumlahAnggota = jumlahAnggota + 1;
this.nomor = jumlahAnggota;
this.nama = nama;
this.kota = kota;
}
static int getJumlahAnggota() {
return jumlahAnggota;
}
int sisaKuotaPinjam(int sedangDipinjam) {
return MAKSIMUM_PINJAM - sedangDipinjam;
}
void tampilkanProfil() {
System.out.println("Anggota #" + nomor + ": " + nama + " dari " + kota);
}
}
AplikasiAnggota.java
Unduh berkaspublic class AplikasiAnggota {
public static void main(String[] args) {
System.out.println("Maksimum pinjam per anggota: " + Anggota.MAKSIMUM_PINJAM);
Anggota dewi = new Anggota("Dewi Lestari", "Jakarta");
System.out.println("Setelah dewi : jumlahAnggota = " + Anggota.jumlahAnggota);
Anggota budi = new Anggota("Budi Santoso", "Surabaya");
System.out.println("Setelah budi : jumlahAnggota = " + Anggota.jumlahAnggota);
Anggota siti = new Anggota("Siti Rahmawati", "Bandung");
System.out.println("Setelah siti : jumlahAnggota = " + Anggota.getJumlahAnggota());
System.out.println("--- profil ---");
dewi.tampilkanProfil();
budi.tampilkanProfil();
siti.tampilkanProfil();
}
}