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.
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 anggota | Modifier | Wajib di-override? |
|---|---|---|
| Method abstrak | abstract fun | Ya, subclass harus menyediakan body |
| Method open konkret | open fun | Tidak, subclass boleh pakai default |
| Method final konkret | fun (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.
// 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:
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.849539999999998Mari kita amati peran tiap bagian:
abstract class Bentuk(val nama: String): class abstrak tidak dapat diinstansiasi langsung. Propertynamabersifat konkret dan otomatis tersedia untuk subclass.abstract fun luas(): Double: method abstrak tanpa body. Setiap subclass wajib menyediakan implementasiluas()yang mengembalikanDouble. Bila subclass tidak meng-override, kompilator melaporkan kesalahan.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.fun ringkasan(): String: method final konkret. Tidak dapat di-override. Method ini memanggilluas()dankeliling()— karena kedua method tersebut bersifatopen/abstract, runtime akan memilih implementasi subclass saat dipanggil. Inilah kekuatan kombinasi method konkret dan abstrak dalam satu class.override fun luas(): Double = sisi * sisipadaPersegi: subclass menyediakan implementasi rumus luas persegi. Karenaluas()adalah method abstrak, override bersifat wajib.- Loop polimorfik
for (b in daftar): variabelbbertipeBentuk. Pemanggilanb.ringkasan()memanggil method konkretBentuk.ringkasan(), tetapiringkasan()memanggilluas()dankeliling()yang bersifat polymorphism — runtime memilih implementasiPersegiatauLingkaransesuai 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.
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:
| Aspek | open class | abstract class |
|---|---|---|
| Dapat diinstansiasi langsung? | Ya | Tidak |
| Dapat memiliki anggota abstrak? | Tidak | Ya |
Anggota open opsional di-override? | Ya | Ya |
| Cocok untuk | Memberi default yang boleh diubah | Memaksa 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 #
- Classes and Inheritance — bagian abstract class pada panduan class Kotlin
- Inheritance — abstract member sebagai bagian dari hierarki inheritance
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.