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:

java Anggota.java
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:

text
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 Bandung

Output tersebut memuat dua bukti sekaligus. Mari kita bedah:

  1. Baris 3 (Anggota.MAKSIMUM_PINJAM): konstanta diakses lewat nama class, bukan lewat object — tepat sebelum object pertama diciptakan. Akses semacam ini hanya mungkin karena member static sudah hidup sejak class dimuat.
  2. Baris 5-10 (new Anggota(...) tiga kali): setiap constructor menjalankan jumlahAnggota = jumlahAnggota + 1, dan nilainya naik dari 1 ke 2 lalu 3. Angka yang terus berlanjut itu membuktikan bahwa ketiga object menulis pada satu variabel yang sama — bukan tiga salinan terpisah yang selalu bernilai 1.
  3. Baris 12 (Anggota.getJumlahAnggota()): method static dipanggil lewat nama class tanpa bantuan object mana pun, dan mengembalikan nilai terkini penghitung bersama.
  4. Baris 14-17 (dewi.tampilkanProfil(); dst.): setiap profil mencetak nomor yang dibekukan saat constructor berjalan. Field instance nomor menunjukkan 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:

java Pelanggaran: field instance dari method static
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 #

Berkas Sumber

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

Anggota.java

Unduh berkas
java
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);
    }
}

AplikasiAnggota.java

Unduh berkas
java
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();
    }
}