Chapter Encapsulation memperkenalkan private sebagai gembok pada field, tetapi private hanyalah satu dari empat tingkat pengaturan akses yang Java sediakan. Setiap field, method, dan constructor di hadapan kita saat ini sedang membawa salah satu dari empat penanda itu — termasuk penanda tak terlihat: kode tanpa modifier sama sekali punya arti khusus. Access modifier menentukan siapa yang boleh menyebut nama sebuah member: class itu sendiri, tetangga satu package, class turunan, atau seluruh dunia. Pada Chapter ini kita petakan keempat tingkat tersebut, membuktikan batasnya lewat program yang berjalan, lalu melihat bagaimana aturannya bergeser ketika class-class hidup di package yang berbeda.
Empat Tingkat Akses #
Java mengenal tepat empat tingkat visibilitas untuk member class. Tabel berikut menjadi peta utama kita — hafalkan polanya, bukan pengecualiannya:
| Modifier | Class yang sama | Package yang sama | Subclass di package lain | Dunia luar |
|---|---|---|---|---|
private | ya | tidak | tidak | tidak |
| tanpa modifier (package-private) | ya | ya | tidak | tidak |
protected | ya | ya | ya | tidak |
public | ya | ya | ya | ya |
Dua hal tentang tabel tersebut layak digarisbawahi. Pertama, protected adalah package-private yang ditambah satu kunci: class turunan di package lain juga boleh masuk — protected selalu memuat seluruh hak akses package-private. Kedua, tingkat kedua tidak punya kata kunci; kebiasaan menyebutnya package-private (kadang default) menegaskan maknanya: hanya anggota package yang boleh melihat. Class top-level sendiri hanya mengenal dua pilihan — public atau tanpa modifier — karena private maupun protected tidak bermakna untuk class yang tidak bersarang di class lain.
Satu Class dengan Empat Tingkat #
Class Buku berikut sengaja memasang keempat tingkat sekaligus agar kita bisa mengamatinya dalam satu pandangan: field judul bersifat private, penulis protected, tahunTerbit package-private, stok public, dan method-nya menyebar di tiga tingkat berbeda:
class Buku {
private String judul;
protected String penulis;
int tahunTerbit;
public int stok;
Buku(String judul, String penulis, int tahunTerbit, int stok) {
this.judul = judul;
this.penulis = penulis;
this.tahunTerbit = tahunTerbit;
this.stok = stok;
}
public String getJudul() {
return judul;
}
protected String inisialPenulis() {
return penulis.substring(0, 1) + ".";
}
String labelRak() {
return judul + " - " + tahunTerbit;
}
private String kodeRahasia() {
return "BK-" + judul.length();
}
public void tampilkanInfo() {
System.out.println(getJudul() + " | " + penulis + " | " + labelRak()
+ " | " + kodeRahasia());
}
}Method tampilkanInfo sengaja memanggil keempat level dari dalam class — bukti bahwa dari dalam class sendiri, semua tingkat terbuka. Pembatasan baru terasa ketika kode berada di luar class.
Percobaan Akses dari Class Lain #
Semua berkas contoh kita hidup di direktori yang sama tanpa deklarasi package, sehingga seluruhnya berada dalam satu package yang sama (package tanpa nama). Pada posisi tersebut, public, protected, dan package-private sama-sama boleh diakses; hanya private yang tertutup:
public class AplikasiAkses {
public static void main(String[] args) {
Buku buku = new Buku("Hujan Bulan Juni", "Sapardi Djoko Damono", 1994, 2);
// public: dapat diakses dari mana pun
System.out.println("stok : " + buku.stok);
System.out.println("judul : " + buku.getJudul());
buku.tampilkanInfo();
// protected dan package-private: masih satu package, tetap boleh
System.out.println("penulis : " + buku.penulis);
System.out.println("inisial : " + buku.inisialPenulis());
System.out.println("label : " + buku.labelRak());
// private: hanya boleh dari dalam class Buku sendiri;
// percobaan melanggarnya ada pada berkas AksesPrivatGagal.java
}
}Output yang Dihasilkan:
stok : 2
judul : Hujan Bulan Juni
Hujan Bulan Juni | Sapardi Djoko Damono | Hujan Bulan Juni - 1994 | BK-16
penulis : Sapardi Djoko Damono
inisial : S.
label : Hujan Bulan Juni - 1994Mari kita bedah hasilnya baris-per-baris:
- Baris 6-8 (
buku.stok,buku.getJudul(),buku.tampilkanInfo()): tiga memberpublicterbaca tanpa hambatan — tingkat ini memang disiapkan untuk kontrak publik class. - Baris 11-13 (
buku.penulis,buku.inisialPenulis(),buku.labelRak()): fieldprotecteddan method package-private ikut terbaca. Ini bukan pengecualian, melainkan konsekuensi kolom kedua tabel: pemanggil berada satu package denganBuku. - Baris 3 pada
Buku.java(private String judul;): satu-satunya member yang tidak muncul di daftar akses. Membacajudulharus lewatgetJudul()— persis pola encapsulation yang kita bangun pada Chapter sebelumnya.
Lalu apa yang terjadi bila kita memaksa menyentuh member private? Berkas berikut mencoba memanggil method kodeRahasia() dari luar class, dan sengaja dibiarkan gagal dikompilasi:
public class AksesPrivatGagal {
public static void main(String[] args) {
Buku buku = new Buku("Hujan Bulan Juni", "Sapardi Djoko Damono", 1994, 2);
System.out.println(buku.kodeRahasia());
}
}Compiler javac menolak berkas tersebut dengan pesan verbatim kodeRahasia() has private access in Buku — gembok private bekerja justru sebelum program berjalan, pada tahap kompilasi.
Akses Lintas Package #
Peta berubah total ketika class-class hidup di package berbeda. Karena berkas contoh pada Course ini dijalankan dari satu direktori datar, contoh lintas package berikut tampil sebagai blok konsep — namun seluruh aturannya adalah perilaku standar javac yang dapat Anda verifikasi sendiri. Bayangkan tiga berkas pada dua package berikut:
package perpustakaan.inti;
public class Buku {
protected String penulis; // terbuka untuk subclass di package mana pun
String kodeInternal; // package-private: hanya se-package
private String judul;
public Buku(String judul, String penulis) {
this.judul = judul;
this.penulis = penulis;
}
public String getJudul() {
return judul;
}
}package perpustakaan.ui;
import perpustakaan.inti.Buku;
public class AplikasiLintas {
public static void main(String[] args) {
Buku buku = new Buku("Hujan Bulan Juni", "Sapardi Djoko Damono");
System.out.println(buku.getJudul()); // public: BOLEH
// System.out.println(buku.penulis); // DITOLAK compiler
// System.out.println(buku.kodeInternal); // DITOLAK compiler
}
}Class AplikasiLintas bukan subclass Buku dan tidak se-package dengan Buku, sehingga hanya member public yang tersisa. Kompiler menolak dua baris yang dikomentari dengan pesan verbatim penulis has protected access in Buku serta kodeInternal is not public in Buku; cannot be accessed from outside package. Nasib protected berbeda pada class turunan: subclass di package lain tetap boleh mengaksesnya, sebagaimana class berikut:
package perpustakaan.koleksi;
import perpustakaan.inti.Buku;
public class BukuFiksi extends Buku {
public BukuFiksi(String judul, String penulis) {
super(judul, penulis);
}
public String namaPenulis() {
return penulis; // protected: BOLEH, karena BukuFiksi adalah subclass
}
}Kata kunci extends dan super(...) pada contoh tersebut adalah materi dua Chapter ke depan; untuk sekarang, cukup catat satu kalimat ringkasnya: kunci protected dibuat khusus untuk skenario “rahasia keluarga” — tertutup bagi dunia luar, terbuka bagi class turunan.
Memilih Modifier yang Tepat #
Aturan praktisnya sederhana: pilih tingkat akses paling ketat yang masih memenuhi kebutuhan. Field instance sebaiknya private secara bawaan, dibuka lewat method bila perlu; method public adalah janji publik yang sulit ditarik karena pemanggil di mana pun berhak bergantung padanya; modifier package-private cocok untuk detail implementasi yang boleh dilihat rekan satu package; dan protected dipakai hemat, hanya ketika kita memang merancang class untuk diwarisi. Konvensi umum juga menyarankan satu class public per berkas — class utama yang namanya sama dengan nama berkas — sementara class pendukung dibiarkan package-private.
Empat tingkat akses kini lengkap di tangan kita — kita bahkan sudah melirik cara protected dirancang bekerja bersama pewarisan. Namun semua member yang kita buat sejauh ini melekat pada object: setiap new mencetak salinan field sendiri. Java juga menyediakan member jenis lain — milik class, dibagi semua object — yang dikelola kata kunci static. Chapter berikutnya membuktikan lewat penghitung bahwa state bersama tersebut benar-benar terbagi.
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.
AksesPrivatGagal.java
Unduh berkaspublic class AksesPrivatGagal {
public static void main(String[] args) {
Buku buku = new Buku("Hujan Bulan Juni", "Sapardi Djoko Damono", 1994, 2);
System.out.println(buku.kodeRahasia());
}
}
AplikasiAkses.java
Unduh berkaspublic class AplikasiAkses {
public static void main(String[] args) {
Buku buku = new Buku("Hujan Bulan Juni", "Sapardi Djoko Damono", 1994, 2);
// public: dapat diakses dari mana pun
System.out.println("stok : " + buku.stok);
System.out.println("judul : " + buku.getJudul());
buku.tampilkanInfo();
// protected dan package-private: masih satu package, tetap boleh
System.out.println("penulis : " + buku.penulis);
System.out.println("inisial : " + buku.inisialPenulis());
System.out.println("label : " + buku.labelRak());
// private: hanya boleh dari dalam class Buku sendiri;
// percobaan melanggarnya ada pada berkas AksesPrivatGagal.java
}
}
Buku.java
Unduh berkasclass Buku {
private String judul;
protected String penulis;
int tahunTerbit;
public int stok;
Buku(String judul, String penulis, int tahunTerbit, int stok) {
this.judul = judul;
this.penulis = penulis;
this.tahunTerbit = tahunTerbit;
this.stok = stok;
}
public String getJudul() {
return judul;
}
protected String inisialPenulis() {
return penulis.substring(0, 1) + ".";
}
String labelRak() {
return judul + " - " + tahunTerbit;
}
private String kodeRahasia() {
return "BK-" + judul.length();
}
public void tampilkanInfo() {
System.out.println(getJudul() + " | " + penulis + " | " + labelRak()
+ " | " + kodeRahasia());
}
}