Hingga Chapter terakhir Section sebelumnya, kita menulis kode yang memisahkan data (variabel) dari perilaku (method) yang mengolah data tersebut. Pendekatan itu natural untuk program kecil, tetapi ketika program membesar — puluhan data yang saling berkaitan dan ratusan baris kode yang menyentuh data yang sama — menjadi sulit menjaga data tetap konsisten. Object-Oriented Programming (OOP) menjawab masalah tersebut dengan menggabungkan data dan perilaku ke dalam satu unit bernama object. Java dirancang sebagai bahasa OOP sejak awal, sehingga memahami cara berpikir OOP adalah prasyarat membaca hampir semua kode Java di dunia nyata. Pada Section ini kita membangun pemahaman OOP bertahap, dimulai dari filosofi dan empat pilar utamanya.

Dari Prosedural ke Berorientasi Objek #

Dalam gaya prosedural, kita menyimpan data di satu tempat lalu mengolahnya dari tempat lain. Data buku perpustakaan bisa hidup sebagai variabel-variabel lepas — judul1, penulis1, tahunTerbit1 — lalu method terpisah mencetak atau memvalidasinya. Setiap buku baru menuntut satu set variabel baru, dan setiap perubahan bentuk data harus disuntikkan ke banyak tempat; duplikasi semacam ini adalah sumber galat yang sulit dilacak.

OOP membalik pola pikirnya: kita mendefinisikan sekali sebuah class yang menjelaskan struktur data beserta perilakunya, lalu mencetak object sebanyak yang dibutuhkan dari class tersebut. Sebuah object membawa datanya sendiri — object buku pertama tidak memengaruhi isi object buku kedua — dan hanya bisa diubah melalui method yang class sediakan. Dengan demikian, tanggung jawab atas data jelas tempatnya: di dalam class yang mendefinisikannya.

Java menerapkan OOP secara ketat. Semua kode harus hidup di dalam class, tidak ada fungsi global yang berdiri sendiri, dan setiap class pada akhirnya diturunkan dari class Object milik pustaka standar. Kata kunci seperti class, new, extends, dan private adalah perkakas utama yang akan kita gunakan sepanjang Section ini.

Empat Pilar OOP #

Teori OOP sering diringkas menjadi empat pilar. Tabel berikut memetakan setiap pilar ke pertanyaan praktis yang pilar tersebut jawab, beserta perkakas Java yang menyertainya:

PilarPertanyaan praktisPerkakas di Java
EncapsulationBagaimana melindungi data agar tidak diubah sembarangan?field private, method akses public
InheritanceBagaimana menggunakan ulang kode yang sudah ada?extends, super
PolymorphismBagaimana satu perintah berperilaku berbeda tiap object?method overriding, dynamic dispatch
AbstractionBagaimana menyembunyikan kerumitan di balik nama yang sederhana?abstract class, interface

Encapsulation menyembunyikan data internal object di balik method. Data saldo rekening bank, misalnya, tidak boleh dikurangi langsung dari luar object; perubahan harus melewati method tarik() yang memeriksa syaratnya. Invarian seperti “saldo tidak pernah negatif” menjadi tanggung jawab satu tempat, bukan harapan pada kebaikan seluruh kode pemanggil.

Inheritance memungkinkan class baru mewarisi field dan method class lama, lalu menambah atau mengubah bagian yang berbeda. Class BukuFiksi mewarisi kemampuan dasar Buku, lalu menambahkan field genre. Kode dasar ditulis sekali dan dipakai berulang.

Polymorphism membuat satu panggilan method menghasilkan perilaku berbeda tergantung object nyata yang ditunjuk variabel. Kode pengolah daftar buku cukup memanggil deskripsi(); JVM yang memilih versi BukuFiksi atau BukuReferensi saat runtime.

Abstraction menyediakan nama sederhana untuk operasi tanpa membebankan detail pelaksanaannya. Method deskripsi() sendiri adalah abstraksi kecil: pemanggil tahu apa yang didapatkan tanpa perlu tahu bagaimana teksnya dirangkai. Bentuk formalnya — abstract class dan interface — dibahas pada Chapter khusus di akhir Section ini.

Empat Pilar dalam Satu Program #

Mari kita lihat keempat pilar bekerja bersama dalam satu program perpustakaan mini. Program berikut mendefinisikan class Buku dengan data terlindungi, class BukuDigital yang mewarisinya, lalu memanggil method yang perilakunya ditentukan saat runtime:

public class ContohEmpatPilar {
    public static void main(String[] args) {
        Buku favorit = new BukuDigital("Laut Bercerita", "Leila S. Chudori", 380);

        System.out.println(favorit.deskripsi());
        favorit.catatPeminjaman();
        System.out.println("Judul: " + favorit.getJudul());
    }
}

class Buku {
    private String judul;
    private String penulis;
    private int jumlahPinjam;

    Buku(String judul, String penulis) {
        this.judul = judul;
        this.penulis = penulis;
    }

    String deskripsi() {
        return "Buku cetak: " + judul + " oleh " + penulis;
    }

    String getJudul() {
        return judul;
    }

    void catatPeminjaman() {
        jumlahPinjam = jumlahPinjam + 1;
        System.out.println("Peminjaman ke-" + jumlahPinjam + " untuk " + judul);
    }
}

class BukuDigital extends Buku {
    private int jumlahHalaman;

    BukuDigital(String judul, String penulis, int jumlahHalaman) {
        super(judul, penulis);
        this.jumlahHalaman = jumlahHalaman;
    }

    @Override
    String deskripsi() {
        return "Buku digital: " + getJudul() + ", " + jumlahHalaman + " halaman";
    }
}

Output yang Dihasilkan:

text
Buku digital: Laut Bercerita, 380 halaman
Peminjaman ke-1 untuk Laut Bercerita
Judul: Laut Bercerita

Beberapa kata kunci pada program di atas belum kita bedah tuntas, dan itu memang disengaja — masing-masing memiliki Chapter sendiri. Untuk sekarang, mari kita amati peta besarnya:

  1. Baris 4 (Buku favorit = new BukuDigital(...)): variabel bertipe Buku menunjuk object buatan class BukuDigital. Perintah new menciptakan object baru di memori; tipe variabel boleh berupa parent dari tipe object nyatanya (pilar polymorphism).
  2. Baris 6 (favorit.deskripsi()): meskipun variabel bertipe Buku, method yang dijalankan adalah versi milik BukuDigital karena JVM memeriksa object nyata saat runtime, bukan tipe variabelnya.
  3. Baris 12-14 (private String judul; ...): field Buku ditandai private sehingga kode luar tidak bisa membaca atau menulis judul secara langsung; satu-satunya pintu masuk adalah method seperti getJudul() (pilar encapsulation).
  4. Baris 25 (class BukuDigital extends Buku): extends menyatakan bahwa BukuDigital mewarisi seluruh field dan method Buku, lalu menambahkan field jumlahHalaman miliknya sendiri (pilar inheritance).
  5. Baris 39 (String deskripsi()): penanda @Override menegaskan bahwa method ini menggantikan versi parent — anotasi ini akan kita bedah pada Chapter Method Overriding.
  6. Baris 8 (favorit.catatPeminjaman()): method warisan Buku tersedia pada object BukuDigital tanpa ditulis ulang — bukti pewarisan memindahkan perilaku secara otomatis.

Empat pilar tersebut bukan sekadar kosakata ujian sertifikasi — pilar adalah alat pengendali kompleksitas. Encapsulation membatasi ruang tempat data bisa rusak, inheritance memangkas duplikasi, polymorphism memungkinkan kode generis, dan abstraction menjaga pemanggil berpikir pada level masalah. Langkah konkret pertama kita adalah membedah dua kata paling mendasar dari semuanya: class sebagai cetak biru dan object sebagai wujud nyatanya — pokok bahasan Chapter berikutnya.

Referensi #

Berkas Sumber

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

ContohEmpatPilar.java

Unduh berkas
java
public class ContohEmpatPilar {
    public static void main(String[] args) {
        Buku favorit = new BukuDigital("Laut Bercerita", "Leila S. Chudori", 380);

        System.out.println(favorit.deskripsi());
        favorit.catatPeminjaman();
        System.out.println("Judul: " + favorit.getJudul());
    }
}

class Buku {
    private String judul;
    private String penulis;
    private int jumlahPinjam;

    Buku(String judul, String penulis) {
        this.judul = judul;
        this.penulis = penulis;
    }

    String deskripsi() {
        return "Buku cetak: " + judul + " oleh " + penulis;
    }

    String getJudul() {
        return judul;
    }

    void catatPeminjaman() {
        jumlahPinjam = jumlahPinjam + 1;
        System.out.println("Peminjaman ke-" + jumlahPinjam + " untuk " + judul);
    }
}

class BukuDigital extends Buku {
    private int jumlahHalaman;

    BukuDigital(String judul, String penulis, int jumlahHalaman) {
        super(judul, penulis);
        this.jumlahHalaman = jumlahHalaman;
    }

    @Override
    String deskripsi() {
        return "Buku digital: " + getJudul() + ", " + jumlahHalaman + " halaman";
    }
}