Interface adalah kontrak yang menyatakan method dan property apa yang harus disediakan oleh class yang mengimplementasikannya. Berbeda dengan abstract class yang membatasi satu superclass, sebuah class Kotlin dapat mengimplementasikan banyak interface sekaligus — menjadikan interface alat utama untuk mendefinisikan kontrak yang dapat dipakai ulang lintas hierarki. Pada chapter ini kita akan mendeklarasikan interface dengan method abstrak dan method default, melihat interface dengan property abstrak, dan mengamati class yang mengimplementasikan tiga interface sekaligus.
Apa Itu Interface #
Interface mirip dengan abstract class — keduanya dapat menyimpan method tanpa body yang harus diimplementasikan oleh class lain. Perbedaan utamanya:
| Aspek | Interface | Abstract class |
|---|---|---|
| Multiple inheritance | Satu class dapat implementasikan banyak interface | Hanya boleh warisi satu abstract class |
| State (field dengan nilai) | Tidak boleh | Boleleh |
| Constructor | Tidak punya | Punya |
| Default method body | Boleleh | Boleleh |
| Property abstrak | Boleleh (tanpa backing field) | Boleleh (dengan backing field) |
Karena interface tidak memiliki state, ia lebih ringan dan cocok untuk menyatakan kemampuan (capability) yang dapat dimiliki banyak class dari hierarki berbeda — misalnya Comparable, Drawable, atau Serializable.
Method Abstrak dan Method Default #
Method dalam interface dapat ditulis dengan dua bentuk:
- Method abstrak — hanya signature tanpa body. Class implementasi wajib menyediakan body.
- Method default — body disediakan oleh interface. Class implementasi dapat memakainya apa adanya atau menggantinya.
interface Bergerak {
fun bergerak(jarak: Int): String {
return "Bergerak sejauh $jarak meter"
}
}Class yang mengimplementasikan Bergerak dapat langsung memanggil bergerak(10) tanpa menulis implementasi sendiri. Method default berguna saat mayoritas class implementasi memerlukan perilaku yang sama — kita menyimpan implementasi sekali di interface dan menghemat duplikasi.
Property pada Interface #
Interface dapat mendeklarasikan property, tetapi property tersebut bersifat abstrak — interface tidak menyediakan backing field. Class implementasi wajib menyediakan property melalui override val atau override var. Interface juga dapat menyediakan getter default untuk property yang nilainya dihitung, namun tidak dapat menyimpan field internal.
interface Berhitung {
val faktor: Int
fun kalikan(x: Int): Int = x * faktor
}Interface Berhitung menyatakan bahwa setiap class implementasi wajib memiliki property faktor. Method kalikan memiliki body default yang membaca property faktor tersebut — saat dipanggil, runtime membaca faktor dari implementasi class.
Contoh Lengkap dengan Tiga Interface #
Contoh berikut mendefinisikan tiga interface — Bersuara, Bergerak, dan Berhitung — lalu membuat class Robot yang mengimplementasikan ketiganya. Class HewanMamalia hanya mengimplementasikan dua interface (Bersuara dan Bergerak), menunjukkan bahwa interface bersifat opsional dan dapat dikombinasikan sesuai kebutuhan.
// interfaces.kt
// Mendemonstrasikan interface, default method, multiple implementation.
interface Bersuara {
fun bersuara(): String
}
interface Bergerak {
fun bergerak(jarak: Int): String {
return "Bergerak sejauh $jarak meter"
}
}
interface Berhitung {
val faktor: Int
fun kalikan(x: Int): Int = x * faktor
}
class Robot(val nama: String) : Bersuara, Bergerak, Berhitung {
override val faktor: Int = 2
override fun bersuara(): String {
return "$nama berbunyi: BEEP BOOP"
}
}
class HewanMamalia(val nama: String) : Bersuara, Bergerak {
override fun bersuara(): String {
return "$nama bersuara umum"
}
}
fun main() {
val r = Robot("R2D2")
println(r.bersuara())
println(r.bergerak(10))
println("Hasil kalikan 5 dengan faktor ${r.faktor}: ${r.kalikan(5)}")
val h = HewanMamalia("Kucing")
println(h.bersuara())
println(h.bergerak(3))
println()
println("Loop polimorfik terhadap Bersuara:")
val daftar: List<Bersuara> = listOf(r, h)
for (x in daftar) {
println("- ${x.bersuara()}")
}
}Output yang Dihasilkan:
R2D2 berbunyi: BEEP BOOP
Bergerak sejauh 10 meter
Hasil kalikan 5 dengan faktor 2: 10
Kucing bersuara umum
Bergerak sejauh 3 meter
Loop polimorfik terhadap Bersuara:
- R2D2 berbunyi: BEEP BOOP
- Kucing bersuara umumMari kita amati interaksi antar interface:
interface Bersuara { fun bersuara(): String }: interface dengan satu method abstrak. Class implementasi wajib menyediakan body untukbersuara().interface Bergerak { fun bergerak(jarak: Int): String { ... } }: interface dengan method default. Class implementasi dapat memakai implementasi default atau menggantinya.interface Berhitung { val faktor: Int; fun kalikan(x: Int): Int = x * faktor }: interface dengan property abstrak dan method default yang membaca property tersebut. Interface tidak menyimpan nilaifaktor— class implementasi yang harus menyediakannya.class Robot(val nama: String) : Bersuara, Bergerak, Berhitung: tanda titik dua diikuti tiga interface dipisah koma. Class mengimplementasikan ketiganya sekaligus — multiple interface implementation.override val faktor: Int = 2: Robot menyediakan propertyfaktoryang dijanjikan interfaceBerhitung. Method defaultkalikandi interface akan membaca nilai ini saat dipanggil melalui instance Robot — bukti bahwa method default dapat bergantung pada property implementasi.r.bergerak(10): Robot tidak meng-overridebergerak(), sehingga method defaultBergerakyang dipanggil. Pemanggilan mengembalikan teks default"Bergerak sejauh 10 meter".r.kalikan(5): pemanggilan method default dari interfaceBerhitung. Body method membaca propertyfaktor(yang disediakan Robot sebagai2), sehingga hasilnya5 * 2 = 10.val daftar: List<Bersuara> = listOf(r, h): variabel bertipeList<Bersuara>dapat menampung instanceRobotdanHewanMamaliakarena keduanya mengimplementasikanBersuara. Loop memanggilx.bersuara()yang dipolimorfik sesuai implementasi masing-masing class.
Multiple Interface Implementation #
Karena sebuah class dapat mengimplementasikan banyak interface, kita dapat menyusun kemampuan secara fleksibel. Class Robot yang mengimplementasikan Bersuara, Bergerak, dan Berhitung dapat diperlakukan sebagai ketiga tipe tersebut bergantung pada konteks. Function yang menerima parameter bertipe Bergerak dapat memproses Robot maupun HewanMamalia tanpa peduli class konkret yang dimasukkan.
fun jarakTotal(bergerak: Bergerak, daftarJarak: List<Int>): Int {
return daftarJarak.sumOf { it }
}Function jarakTotal menerima argumen bertipe Bergerak — apa pun class konkret yang dimasukkan, selama mengimplementasikan Bergerak, function dapat memprosesnya. Tambah class baru yang mengimplementasikan Bergerak, dan function tetap bekerja tanpa perubahan.
Konflik Method Default #
Bila dua interface yang diimplementasikan memiliki method default dengan signature sama, class implementasi harus menyelesaikan konflik dengan meng-override method tersebut secara eksplisit. Override dapat memanggil implementasi salah satu interface melalui super<InterfaceName>.method().
interface A { fun foo() = "A" }
interface B { fun foo() = "B" }
class C : A, B {
override fun foo(): String {
return super<A>.foo() + " dan " + super<B>.foo()
}
}Tanpa override eksplisit, kompilator akan menolak deklarasi C : A, B karena ambigu.
Referensi Lanjutan #
- Interfaces — panduan resmi deklarasi interface dan method default
Ringkasan #
Interface adalah kontrak yang menyatakan method dan property apa yang harus disediakan class implementasi. Interface dapat memiliki method default dan property abstrak, namun tidak boleh memiliki state atau constructor. Sebuah class Kotlin dapat mengimplementasikan banyak interface sekaligus, memberikan fleksibilitas yang tidak dimiliki abstract class. Pada chapter Interface Delegation berikutnya, kita akan melihat bagaimana class dapat mendelegasikan implementasi interface ke object lain.