Java memiliki pendekatan OOP yang sangat ketat dan konsisten — single inheritance untuk class, multiple interface, dan semua method virtual secara default. Ini berbeda dari C++ yang memungkinkan multiple inheritance class, dan mirip dengan C# tapi dengan perbedaan sintaks. Di artikel ini kita akan mempelajari cara membangun hierarki class di Java.
Inheritance dengan extends
// Superclass (parent class)
public class Hewan {
protected String nama;
protected int umur;
public Hewan(String nama, int umur) {
this.nama = nama;
this.umur = umur;
}
public void makan() {
System.out.println(nama + " sedang makan.");
}
public String getInfo() {
return String.format("%s (umur %d tahun)", nama, umur);
}
}
// Subclass menggunakan extends
public class Anjing extends Hewan {
private String ras;
public Anjing(String nama, int umur, String ras) {
super(nama, umur); // Wajib panggil constructor superclass pertama
this.ras = ras;
}
public void gonggong() {
System.out.println(nama + " (" + ras + "): Guk guk!");
}
@Override // Annotation — compiler verifikasi bahwa ini memang override
public String getInfo() {
return super.getInfo() + " | Ras: " + ras;
}
}
// Main.java
Anjing anjing = new Anjing("Buddy", 3, "Labrador");
anjing.makan(); // Mewarisi dari Hewan
anjing.gonggong(); // Method sendiri
System.out.println(anjing.getInfo()); // Override dari Hewan
// Output:
// Buddy sedang makan.
// Buddy (Labrador): Guk guk!
// Buddy (umur 3 tahun) | Ras: Labrador
Polymorphism dan Upcasting
public class Kucing extends Hewan {
public Kucing(String nama, int umur) { super(nama, umur); }
@Override
public String getInfo() { return super.getInfo() + " (Kucing)"; }
}
// Upcasting: subclass bisa disimpan dalam referensi superclass
Hewan h1 = new Anjing("Max", 2, "Poodle"); // Anjing IS-A Hewan
Hewan h2 = new Kucing("Mochi", 1); // Kucing IS-A Hewan
Hewan[] hewan_hewan = { h1, h2, new Anjing("Rex", 4, "German Shepherd") };
for (Hewan h : hewan_hewan) {
System.out.println(h.getInfo()); // Polimorfis: memanggil versi yang tepat
h.makan();
}
// Downcasting (harus hati-hati)
if (h1 instanceof Anjing anjing) { // Pattern matching instanceof (Java 16+)
anjing.gonggong(); // Akses method Anjing setelah verifikasi tipe
}
Abstract Class
public abstract class Pegawai {
protected String nama;
protected double gajiPokok;
public Pegawai(String nama, double gajiPokok) {
this.nama = nama;
this.gajiPokok = gajiPokok;
}
// Abstract method: WAJIB diimplementasikan subclass
public abstract double hitungGaji();
public abstract String getJabatan();
// Non-abstract: shared untuk semua subclass
public void cetakSlipGaji() {
System.out.println("=== Slip Gaji ===");
System.out.printf("Nama : %s%n", nama);
System.out.printf("Jabatan : %s%n", getJabatan());
System.out.printf("Gaji : Rp %,.0f%n", hitungGaji());
}
}
public class PegawaiTetap extends Pegawai {
private double tunjangan;
public PegawaiTetap(String nama, double gajiPokok, double tunjangan) {
super(nama, gajiPokok);
this.tunjangan = tunjangan;
}
@Override
public double hitungGaji() { return gajiPokok + tunjangan; }
@Override
public String getJabatan() { return "Pegawai Tetap"; }
}
public class Kontrak extends Pegawai {
private int jamKerja;
public Kontrak(String nama, double tarifPerJam, int jam) {
super(nama, tarifPerJam);
this.jamKerja = jam;
}
@Override
public double hitungGaji() { return gajiPokok * jamKerja; }
@Override
public String getJabatan() { return "Karyawan Kontrak"; }
}
// new Pegawai("Ali", 5000000); // ❌ Error: abstract class!
PegawaiTetap pt = new PegawaiTetap("Ali", 8_000_000, 2_000_000);
Kontrak k = new Kontrak("Budi", 150_000, 40);
pt.cetakSlipGaji();
k.cetakSlipGaji();
// Output:
// === Slip Gaji ===
// Nama : Ali
// Jabatan : Pegawai Tetap
// Gaji : Rp 10.000.000
// === Slip Gaji ===
// Nama : Budi
// Jabatan : Karyawan Kontrak
// Gaji : Rp 6.000.000
Interface di Java
// Interface mendefinisikan kontrak — class WAJIB implementasi semua methodnya
public interface Bisa_Terbang {
void terbang();
double getKetinggianMaks();
// default method (Java 8+) — bisa punya implementasi!
default String deskripsiTerbang() {
return "Bisa terbang hingga " + getKetinggianMaks() + " meter";
}
}
public interface Bisa_Berenang {
void renang();
}
// Class bisa implements banyak interface (berbeda dengan extends yang hanya 1)
public class Bebek extends Hewan implements Bisa_Terbang, Bisa_Berenang {
public Bebek(String nama, int umur) { super(nama, umur); }
@Override
public void terbang() { System.out.println(nama + ": Wek wek (terbang pendek)"); }
@Override
public double getKetinggianMaks() { return 50.0; }
@Override
public void renang() { System.out.println(nama + ": Berenang di danau"); }
}
Bebek b = new Bebek("Donald", 2);
b.terbang();
b.renang();
System.out.println(b.deskripsiTerbang()); // default method
// Output:
// Donald: Wek wek (terbang pendek)
// Donald: Berenang di danau
// Bisa terbang hingga 50.0 meter
Pertanyaan yang Sering Diajukan
Apa perbedaan extends dan implements di Java?
extends digunakan untuk mewarisi class (hanya boleh satu class) atau memperluas interface (boleh lebih dari satu). implements digunakan saat class mengimplementasikan satu atau lebih interface. Sebuah class bisa sekaligus menggunakan keduanya: class Bebek extends Hewan implements Bisa_Terbang, Bisa_Berenang.
Mengapa semua method di Java bersifat virtual secara default?
Ini adalah keputusan desain Java untuk mendukung polymorphism sepenuhnya. Di C++, kamu harus eksplisit menandai method sebagai virtual. Di Java, semua method instance bisa di-override oleh subclass tanpa kata kunci tambahan — kamu hanya perlu @Override. Jika ingin mencegah override, gunakan final pada method.
Apa manfaat default method pada interface (Java 8+)?
Sebelum Java 8, menambahkan method baru ke interface yang sudah banyak diimplementasikan berarti semua class yang mengimplementasikannya harus menambahkan implementasi baru — breaking change. default method memungkinkan kamu menambahkan method baru ke interface dengan implementasi default, sehingga class yang sudah ada tidak perlu diubah.
Kapan menggunakan abstract class vs interface di Java?
Gunakan abstract class saat kamu ingin berbagi kode (implementasi) antar class yang saling berhubungan erat, atau saat perlu field (state) dan constructor. Gunakan interface saat mendefinisikan kontrak perilaku yang bisa diterapkan ke class yang tidak saling berhubungan. Aturan praktis: jika hubungannya “IS-A” dengan shared state, gunakan abstract class; jika “CAN-DO” (bisa terbang, bisa berenang), gunakan interface.
Kesimpulan
| Konsep | Java | C# | C++ |
|---|---|---|---|
| Inheritance | extends (max 1 class) | : BaseClass | : public Base |
| Interface | implements (banyak) | : IInterface | Pure abstract class |
| Virtual default | ✅ Semua method | virtual keyword | ❌ (harus eksplisit) |
| Override marker | @Override annotation | override keyword | override keyword |
| Abstract method | abstract keyword | abstract keyword | = 0 (pure virtual) |
| Prevent inherit | final | sealed | Tidak ada keyword |
Artikel sebelumnya: Class dan Object di Java — membuat class dasar di Java.
Langkah selanjutnya: Exception Handling di Java — cara menangani error dengan try/catch/throw, termasuk konsep checked vs unchecked exception yang unik di Java.