Abstract class adalah class yang sengaja dirancang tidak lengkap — sebagian anggotanya dideklarasikan tanpa implementasi dan harus diisi oleh subclass. Berbeda dengan class open yang menyediakan implementasi default opsional untuk di-override, abstract class memaksa subclass menyediakan implementasi tertentu melalui kontrak yang tidak boleh dilewati. Pada chapter ini kita akan mendeklarasikan abstract class Bentuk dengan method abstrak luas(), melihat perbedaan method abstrak dengan method open, dan mengamati bagaimana abstract class bekerja dalam loop polimorfik.

Mengapa Abstract Class Diperlukan #

Beberapa class memang tidak masuk akal diinstansiasi sendirian. Class Bentuk secara konseptual adalah gagasan umum — kita tidak tahu menghitung luas sebuah “bentuk” tanpa tahu bentuknya konkret. Yang masuk akal adalah subclass seperti Persegi, Lingkaran, atau Segitiga yang masing-masing memiliki rumus luas sendiri.

Abstract class menyatakan dengan jelas bahwa class ini tidak boleh dipakai langsung. Kompilator menolak pemanggilan Bentuk("X") — hanya subclass konkret yang dapat diinstansiasi. Abstract class juga menjadi tempat menyimpan kontrak: setiap subclass wajib menyediakan method luas() yang mengembalikan Double.

Sintaks Abstract Class #

Abstract class dideklarasikan dengan keyword abstract sebelum class. Anggota abstrak — property atau method — juga ditandai abstract dan tidak memiliki body. Subclass wajib meng-override anggota abstrak dengan keyword override.

kotlin Contoh: kerangka abstract class
abstract class Bentuk(val nama: String) {
    abstract fun luas(): Double
    open fun keliling(): Double = 0.0
    fun ringkasan(): String = "$nama: luas=${luas()}"
}

Tiga jenis anggota dapat berdampingan dalam satu abstract class:

Jenis anggotaModifierWajib di-override?
Method abstrakabstract funYa, subclass harus menyediakan body
Method open konkretopen funTidak, subclass boleh pakai default
Method final konkretfun (tanpa modifier)Tidak, tidak bisa di-override sama sekali

Abstract Class Tidak Dapat Diinstansiasi #

Karena class abstrak menyatakan dirinya tidak lengkap, kompilator melarang instansiasi langsung. Kode Bentuk("X") akan ditolak. Hanya subclass konkret yang meng-override seluruh anggota abstrak dapat diinstansiasi. Aturan ini memastikan tidak ada object yang berada dalam keadaan setengah jadi.

Contoh Lengkap Hierarki Bentuk #

Contoh berikut mendefinisikan abstract class Bentuk dengan satu method abstrak luas(), satu method open keliling(), dan satu method final ringkasan(). Subclass Persegi dan Lingkaran meng-override kedua method yang dapat di-override dan menyediakan rumus masing-masing.

kotlin
// abstract_classes.kt
// Mendemonstrasikan abstract class dengan property dan method abstrak.

abstract class Bentuk(val nama: String) {
    // Method abstrak: wajib di-override subclass, tidak punya body.
    abstract fun luas(): Double

    // Method open konkret: opsional di-override subclass.
    open fun keliling(): Double = 0.0

    // Method konkret final: tidak bisa di-override.
    fun ringkasan(): String {
        return "$nama: luas=${luas()}, keliling=${keliling()}"
    }
}

class Persegi(nama: String, val sisi: Double) : Bentuk(nama) {
    override fun luas(): Double = sisi * sisi
    override fun keliling(): Double = 4 * sisi
}

class Lingkaran(nama: String, val jari: Double) : Bentuk(nama) {
    override fun luas(): Double = 3.14159 * jari * jari
    override fun keliling(): Double = 2 * 3.14159 * jari
}

fun main() {
    val p = Persegi("Persegi A", 5.0)
    val l = Lingkaran("Lingkaran B", 3.0)

    println(p.ringkasan())
    println(l.ringkasan())

    println()
    println("Loop abstrak:")
    val daftar: List<Bentuk> = listOf(p, l)
    for (b in daftar) {
        println("- ${b.ringkasan()}")
    }
}

Output yang Dihasilkan:

text
Persegi A: luas=25.0, keliling=20.0
Lingkaran B: luas=28.274309999999996, keliling=18.849539999999998

Loop abstrak:
- Persegi A: luas=25.0, keliling=20.0
- Lingkaran B: luas=28.274309999999996, keliling=18.849539999999998

Mari kita amati peran tiap bagian:

  1. abstract class Bentuk(val nama: String): class abstrak tidak dapat diinstansiasi langsung. Property nama bersifat konkret dan otomatis tersedia untuk subclass.
  2. abstract fun luas(): Double: method abstrak tanpa body. Setiap subclass wajib menyediakan implementasi luas() yang mengembalikan Double. Bila subclass tidak meng-override, kompilator melaporkan kesalahan.
  3. open fun keliling(): Double = 0.0: method konkret dengan implementasi default. Subclass boleh meng-override tetapi tidak wajib. Pada contoh, kedua subclass memilih meng-override.
  4. fun ringkasan(): String: method final konkret. Tidak dapat di-override. Method ini memanggil luas() dan keliling() — karena kedua method tersebut bersifat open/abstract, runtime akan memilih implementasi subclass saat dipanggil. Inilah kekuatan kombinasi method konkret dan abstrak dalam satu class.
  5. override fun luas(): Double = sisi * sisi pada Persegi: subclass menyediakan implementasi rumus luas persegi. Karena luas() adalah method abstrak, override bersifat wajib.
  6. Loop polimorfik for (b in daftar): variabel b bertipe Bentuk. Pemanggilan b.ringkasan() memanggil method konkret Bentuk.ringkasan(), tetapi ringkasan() memanggil luas() dan keliling() yang bersifat polymorphism — runtime memilih implementasi Persegi atau Lingkaran sesuai tipe asli object.

Abstract Property #

Selain method, property juga dapat bersifat abstrak. Property abstrak tidak memiliki initializer dan tidak memiliki default getter/setter. Subclass wajib menyediakan implementasi property melalui override val atau override var.

kotlin Contoh: abstract property
abstract class Pegawai {
    abstract val id: String
    abstract val gaji: Double
}

class Staf(override val id: String, override val gaji: Double) : Pegawai()

Property abstrak berguna saat superclass ingin memaksa subclass menyediakan data tertentu tetapi tidak ingin mengasumsikan bagaimana data tersebut disimpan — apakah sebagai field biasa, hasil komputasi, atau dari sumber eksternal.

Perbandingan Abstract Class vs open Class #

Tabel berikut merangkum perbedaan utama:

Aspekopen classabstract class
Dapat diinstansiasi langsung?YaTidak
Dapat memiliki anggota abstrak?TidakYa
Anggota open opsional di-override?YaYa
Cocok untukMemberi default yang boleh diubahMemaksa kontrak tertentu

Pilih open class bila superclass sudah menyediakan implementasi lengkap dan subclass boleh memilih untuk menyesuaikan. Pilih abstract class bila superclass tidak masuk akal tanpa subclass konkret, atau bila ada method yang wajib disediakan subclass.

Referensi Lanjutan #

Ringkasan #

Abstract class adalah class yang sengaja tidak lengkap, memaksa subclass menyediakan implementasi anggota abstrak. Method abstrak tidak memiliki body dan wajib di-override; method open konkret menyediakan default opsional; method final konkret tidak dapat di-override sama sekali. Abstract class tidak dapat diinstansiasi langsung, tetapi dapat menyimpan constructor yang dipanggil subclass. Pada chapter Interfaces berikutnya, kita akan melihat konsep serupa yang lebih ringan — interface hanya berisi kontrak tanpa state, dan sebuah class dapat mengimplementasikan banyak interface sekaligus.