Kotlin OOP: Mengenal Pewarisan/Inheritance
Pewarisan atau disebut inheritance merupakan fitur yang sangat penting dari pemrograman OOP. OOP tanpa pewarisan bagaikan tubuh tanpa darah. Sebenarnya apa itu pewarisan? Apa guna pewarisan? Lalu, Bagaimana pewarisan di bahasa Kotlin?
Mengapa Kita Membutuhkan Pewarisan?
Pewarisan sangat berguna jika terdapat kelas yang mempunyai kesamaan anggota. Untuk lebih jelasnya kalian bisa lihat kasus di bawah ini.
Terdapat kelas yang bernama Mobil
. Kelas ini memiliki properti warna
dan produsen
. Kelas ini
juga memiliki fungsi bernama hidupkan
dan matikan
. Deklarasi kelasnya seperti ini:
class Mobil {
val warna = "Apapun"
val produsen = "Apapun"
fun hidupkan() {
println("Mobil dihidupkan")
}
fun matikan() {
println("Mobil dimatikan")
}
}
Kemudian kita ingin membuat kelas bernama Avanza
. Kita ingin kelas Avanza
mempunyai anggota yang
sama dengan anggota kelas Mobil
. Mungkin kita bisa copy paste kode dari kelas Mobil
ke Avanza
.
Jadi kelasnya seperti ini:
class Avanza {
val warna = "Apapun"
val produsen = "Apapun"
fun hidupkan() {
println("Mobil dihidupkan")
}
fun matikan() {
println("Mobil dimatikan")
}
}
Tetapi cara ini kurang efisien. Pada permasalahan ini kita bisa menggunakan Pewarisan/Inheritance.
Apa Itu Pewarisan?
Pewarisan atau inheritance adalah fitur pemrograman OOP yang memungkinkan kita mewariskan anggota suatu kelas ke kelas lain. Apa maksud dari mewariskan anggota? Untuk memahaminya kita bisa terapkan pada contoh tadi.
Kelas Avanza
bisa mewarisi anggota (properti dan fungsi) dari kelas Mobil
. Artinya di dalam
kelas Avanza
akan terdapat semua anggota kelas Mobil
. Kelas Avanza
akan memiliki properti yang
merupakan properti kelas Mobil
yaitu warna
dan produsen
. Kelas Avanza
juga akan memiliki
fungsi yang berasal dari kelas Mobil
yaitu hidupkan
dan matikan
.
Pada pewarisan sifat terdapat istilah kelas induk atau super class dan kelas turunan atau sub
class. Kelas induk adalah kelas yang anggotanya diwariskan ke kelas lain. Sedangkan kelas turunan
adalah kelas yang mewarisi anggota kelas lain. Pada contoh di atas kelas Mobil
adalah kelas induk
dan kelas Avanza
adalah kelas turunan.
Pewarisan di Kotlin
Kita bisa menulis ulang kelas Avanza
agar lebih ringkas dengan pewarisan. Kelas Avanza
bisa
mewarisi kelas Mobil
sehingga kita tidak perlu mendeklarasikan ulang anggota-anggotanya. Kodenya
menjadi seperti ini:
class Avanza : Mobil() {
}
Sekarang kode terlihat sangat ringkas.
Pada bahasa pemrograman Kotlin pewarisan sifat bisa dilakukan dengan menggunakan titik dua (:
)
setelah nama kelas. Mobil()
menentukan cara memanggil konstruktor kelas Mobil
saat objek dari
kelas Avanza
dibuat.
Terdapat error pada kode di atas yang mempunyai pesan
this type is final, so it cannot be inherited from
. Error ini terjadi karena kelas Mobil
adalah
kelas final. Pada Kotin semua kelas secara default adalah kelas final. Kelas final adalah
kelas yang tidak dapat diwariskan.
Lalu bagaimana cara untuk mengatasi error ini?. Caranya dengan mengubah kelas Mobil
menjadi kelas
open. Kelas open merupakan kebalikan kelas final. Kelas open merupakan kelas yang dapat
diwariskan.
Untuk mengubah kelas Mobil
menjadi kelas open kita hanya perlu menambahkan keywordopen
sebelum class
di deklarasi kelas tersebut. Beginilah jadinya deklarasi kelasnya:
open class Mobil {
// ...
}
Error tadi seketika hilang!
Sekarang mari kita coba jalankan kode ini:
val avanza = Mobil()
println(avanza.warna) // Apapun
println(avanza.produsen) // Apapun
Terlihat bahwa saat kita mengakses properti warna
pada kelas Avanza
maka yang diakses adalah
properti warna
milik kelas Mobil
. Begitu juga dengan properti produsen
.
Lalu jalankan kode ini:
avanza.hidupkan() // Mobil dihidupkan
avanza.matikan() // Mobil dimatikan
Terlihat bahwa pada saat kita memanggil fungsi matikan
pada kelas Avanza
maka yang terpanggil
adalah fungsi matikan
milik kelas Mobil
. Begitu juga dengan fungsi hidupkan
.
Override Fungsi dan Properti
Bagaimana caranya agar fungsi matikan
milik kelas Mobil
tidak dipanggil saat fungsi matikan
milik kelas Avanza
dipanggil?. Untuk melakukan ini kita bisa men-override fungsi tersebut.
Override memungkinkan kita untuk mengimplementasikan ulang fungsi atau properti pada kelas induk yang diturunkan ke kelas anak.
Misalkan kita ingin mengimplementasikan ulang fungsi hidupkan
, fungsi matikan
, properti
produsen
dan properti warna
pada kelas Avanza
. Kode seperti berikut:
class Avanza : Mobil() {
override val warna = "Merah"
override val produsen = "Toyota"
override fun hidupkan() {
println("Avanza dihidupkan")
}
override fun matikan() {
println("Avanza dimatikan")
}
}
Namun kode kita ternyata ada banyak error seperti ini:
error: 'warna' in 'Mobil' is final and cannot be overridden
override val warna = "Merah"
^
error: 'produsen' in 'Mobil' is final and cannot be overridden
override val produsen = "Toyota"
^
error: 'hidupkan' in 'Mobil' is final and cannot be overridden
override fun hidupkan() {
^
error: 'matikan' in 'Mobil' is final and cannot be overridden
override fun matikan() {
^
Apa maksudnya? Ternyata fungsi hidupkan
, fungsi matikan
, properti produsen
dan properti
warna
berstatus final. Semua anggota kelas secara default berstatus final. Ini mirip dengan
kelas final. Anggota kelas yang berstatus final tidak dapat di-override.
Lalu bagaimana cara mengatasinya? Caranya dengan mengubah keempat anggota kelas tadi menjadi berstatus open. Anggota kelas yang berstatus open bisa di-override
Untuk mengubahnya kita tinggal menambah keyword open sebelum deklarasi fungsi (fun
) atau
variabel (val
/var
). Deklarasi kelas Mobil
akan menjadi begini:
open class Mobil {
open val warna = "Apapun"
open val produsen = "Apapun"
open fun hidupkan() {
println("Mobil dihidupkan")
}
open fun matikan() {
println("Mobil dimatikan")
}
}
Seketika semua error di atas menghilang!
Deklarasi fungsi atau properti harus diberi awalan keyword override
. Coba kalian jalankan kode
seperti ini lagi dan lihat hasilnya:
println(avanza.warna) // Merah
println(avanza.produsen) // Toyota
avanza.hidupkan() // Avanza dihidupkan
avanza.matikan() // Avanza dimatikan
Terlihat setelah kita men-override 2 fungsi di atas, fungsi induk tidak dipanggil saat kedua fungsi dipanggil. Begitu juga dengan 2 properti di atas, properti induk tidak diakses saat kedua fungsi dipanggil.
Memanggil Fungsi Induk dari Kelas Anak
Kadang kita perlu memanggil fungsi milik kelas induk dari kelas Anak khususnya saat men-override
fungsi. Untuk memanggil fungsi induk dari kelas anak kita bisa menggunakan super
.
Contohnya saat fungsi hidupkan
dari kelas Avanza
dipanggil maka fungsi hidupkan
kelas Mobil
dipanggil pada awal fungsi. Sedangkan saat fungsi matikan
dari kelas Avanza
dipanggil maka
fungsi matikan
kelas Mobil
dipanggil pada akhir fungsi. Kodenya seperti ini:
class Avanza : Mobil {
// kodenya sama
override fun hidupkan() {
super.hidupkan()
println("Avanza dihidupkan")
}
override fun matikan() {
println("Avanza dimatikan")
super.matikan()
}
}
Jalankan kode di bawah dan lihat hasilnya:
avanza.hidupkan()
// Mobil dihidupkan
// Avanza dihidupkan
avanza.matikan()
// Avanza dimatikan
// Mobil dimatikan
Terlihat bahwa fungsi hidupkan
dan matikan
dari kelas Mobil
terpanggil.