Menguasai pilar keempat OOP: abstract class untuk state dan implementasi parsial, interface untuk kontrak murni dengan default, static dan private methods, sealed interface untuk hierarki tertutup, serta panduan kapan memilih mana di desain nyata.

Empat pilar OOP kita akhiri di pilar yang paling strategis: abstraction — memisahkan "apa yang bisa dilakukan" dari "bagaimana melakukannya". Java memberi dua senjata: abstract class dan interface. Memilih di antara keduanya dengan tepat adalah salah satu skill desain yang paling sering ditanyakan di dunia kerja.
Mengapa episode ini penting? Karena hampir semua framework Java yang kalian temui — Spring, Hibernate, koleksi Java — dibangun di atas kontrak abstraction. Kemampuan membaca dan merancang kontrak inilah yang membedakan programmer yang menyalin kode dari programmer yang mendesain sistem.
Abstract class adalah class yang tidak bisa di-instantiate — tidak bisa new langsung. Ia menjadi kerangka bagi subclass. Tandanya: keyword abstract pada class dan/atau method.
public abstract class Akun {
protected String pemilik;
protected double saldo;
public Akun(String pemilik, double saldo) {
this.pemilik = pemilik;
this.saldo = saldo;
}
public void deposit(double nominal) {
saldo += nominal;
}
public abstract void laporan();
}Perhatikan dua bagian:
deposit) — implementasi yang diwarisi semua subclass. Ini "shared state & partial implementation".laporan()) — hanya kontrak; subclass wajib mengimplementasikannya.public class RekeningTabungan extends Akun {
public RekeningTabungan(String pemilik, double saldo) {
super(pemilik, saldo);
}
@Override
public void laporan() {
System.out.println("Tabungan " + pemilik + ": " + saldo);
}
}Kekuatan abstract class: state dibagikan (field pemilik, saldo) dan implementasi umum dibagi (deposit). Subclass hanya menambahkan yang spesifik. Ini cocok ketika class-class terkait berbagi banyak hal nyata.
Interface adalah kontrak tanpa state. Di Java modern, interface mendeklarasikan method (dan beberapa bentuk default/static/private), dan class menandatangani kontrak dengan implements.
public interface Pembayaran {
boolean proses(double nominal);
}public class TransferBank implements Pembayaran {
@Override
public boolean proses(double nominal) {
System.out.println("Transfer bank " + nominal);
return true;
}
}Perbedaan kunci dari abstract class: interface tidak punya state. Ia hanya mendefinisikan perilaku. Karena itu satu class bisa implements banyak interface, tetapi hanya bisa extends satu class — Java tidak punya multiple inheritance untuk class.
Sejak Java 8, interface tidak lagi "hampa":
default method — implementasi default yang bisa di-override implementor. Diciptakan agar interface bisa berkembang tanpa memecah implementor lama.static method — helper milik interface, dipanggil lewat nama interface.private method — helper internal yang dipakai bersama default/static method, tidak terlihat luar.public interface Pembayaran {
boolean proses(double nominal);
default void prosesDenganLog(double nominal) {
log("Memulai pembayaran " + nominal);
proses(nominal);
log("Selesai");
}
static void log(String pesan) {
System.out.println("[LOG] " + pesan);
}
}default memberi fleksibilitas evolusi tanpa merusak implementor — ini yang dipakai Java Collections saat menambah method ke List di Java 8.
Ini pertanyaan favorit saat wawancara kerja:
| Kebutuhan | Pilih |
|---|---|
| Berbagi state (field) antar class | Abstract class |
| Berbagi implementasi nyata yang dimodifikasi subclass | Abstract class |
| Mendefinisikan kontrak perilaku murni | Interface |
| Satu class butuh beberapa "peran" | Interface (multiple implements) |
| Relasi "is-a" yang dekat & berbagi banyak | Abstract class |
| API yang harus berkembang tanpa memecah pemakai | Interface (default) |
Aturan praktis dari banyak codebase modern: mulai dengan interface untuk kontrak, gunakan abstract class hanya saat benar-benar butuh berbagi state. Kalian bahkan bisa menggabungkan: interface mendefinisikan kontrak, abstract class menyediakan implementasi dasar yang meng-implements interface itu.
Tip
Analoginya: interface adalah daftar isi kontrak — "pekerjaan apa yang harus dilakukan". Abstract class adalah template dokumen — sudah ada kerangka dan beberapa paragraf terisi, tinggal kalian isi bagian yang kosong.
Interface biasa terbuka: class apa pun bisa implements dari mana saja. Kadang kita ingin hierarki tertutup — hanya tipe tertentu yang boleh. Di sinilah sealed bekerja:
public sealed interface Bentuk
permits Lingkaran, Persegi, Segitiga {
double luas();
}Hanya Lingkaran, Persegi, dan Segitiga yang boleh mengimplementasikannya. Tipe lain di luar permits akan error compile. Keuntungannya: ketika kalian menulis switch atas Bentuk, compiler bisa memastikan semua kasus tercakup — tidak ada cabang yang terlupakan (dipakai penuh dengan pattern matching di episode 10).
Interface yang terlalu banyak method memaksa implementor menulis method yang tidak relevan — misal Pembayaran punya proses() dan juga gantiPIN() yang hanya berlaku untuk kartu. Ini melanggar Interface Segregation (episode 14). Pecah kontrak per peran:
public interface Pembayaran {
boolean proses(double nominal);
}
public interface GantiPIN {
void gantiPIN(String pinLama, String pinBaru);
}Class KartuDebit meng-implements dua-duanya; TransferBank cukup yang pertama. Interface kecil lebih mudah diuji, dipakai ulang, dan dipahami.
Inti yang harus dibawa pulang:
new; subclass menyelesaikan method abstract.default, static, dan private method untuk evolusi yang aman.sealed interface membatasi hierarki — cocok dengan pattern matching.Di episode 10 selanjutnya kita akan membahas enum, record & sealed class — tipe data yang merepresentasikan kumpulan konstan, data carrier immutable, dan hierarki class tertutup, plus switch pattern matching. Sampai jumpa di episode 10!