1. Sebelum memulai
Prasyarat
- Telah terbiasa menggunakan Kotlin Playground untuk mengedit program Kotlin.
- Memahami konsep dasar pemrograman di Kotlin seperti yang dijelaskan dalam Unit 1 pada kursus ini. Secara khusus, program
main()
berfungsi dengan argumen yang menampilkan nilai, variabel, jenis data, dan operasi, serta pernyataanif/else
. - Mampu menetapkan class di Kotlin, membuat instance objek darinya, serta mengakses properti dan metodenya.
Yang akan Anda pelajari
- Membuat program Kotlin yang menggunakan pewarisan untuk menerapkan hierarki class.
- Memperluas class, mengganti fungsi yang sudah ada, dan menambahkan fungsi baru.
- Memilih pengubah visibilitas yang benar untuk variabel.
Yang akan Anda build
- Program Kotlin dengan berbagai jenis tempat tinggal yang diterapkan sebagai hierarki class.
Yang Anda perlukan
- Komputer dengan koneksi internet untuk mengakses Kotlin Playground
2. Apa yang dimaksud dengan hierarki class?
Wajar bagi manusia untuk mengklasifikasikan item yang memiliki properti dan perilaku serupa ke dalam beberapa grup dan bahkan membentuk beberapa jenis hierarki. Misalnya, Anda dapat memiliki kategori yang luas seperti sayuran, dan di dalamnya Anda dapat memiliki jenis yang lebih spesifik seperti polong-polongan. Di dalam polong-polongan, Anda dapat memiliki jenis yang lebih spesifik seperti kacang polong, kacang, lentil, chick pea, dan kedelai.
Contoh di atas dapat diwakili sebagai hierarki karena polong-polongan mengandung atau mewarisi semua sifat-sifat sayuran (misalnya, tanaman dan dapat dimakan). Demikian pula, kacang polong, kacang, dan lentil juga memiliki sifat polong-polongan ditambah sifat uniknya sendiri.
Mari lihat cara Anda mewakili hubungan ini dalam istilah pemrograman. Jika Anda menjadikan Vegetable
sebagai class di Kotlin, Anda dapat membuat Legume
sebagai turunan atau subclass dari class Vegetable
. Ini berarti semua properti dan metode class Vegetable
diwarisi oleh (artinya juga tersedia di) class Legume
.
Anda dapat mewakili hal ini dalam diagram hierarki class seperti yang ditunjukkan di bawah ini. Anda dapat merujuk ke Vegetable
sebagai induk atau superclass dari class Legume
.
Anda dapat melanjutkan dan memperluas hierarki class dengan membuat subclass Legume
seperti Lentil
dan Chickpea
. Ini akan membuat Legume
sebagai turunan atau subclass Vegetable
serta induk atau superclass Lentil
dan Chickpea
. Vegetable
adalah class root atau level atas (atau dasar) dari hierarki ini.
Pewarisan di Class Android
Meskipun Anda dapat menulis kode Kotlin tanpa menggunakan class, dan Anda telah melakukannya di codelab sebelumnya, ada banyak bagian Android yang diberikan kepada Anda dalam bentuk class, seperti aktivitas, tampilan, dan kelompok tampilan. Oleh karena itu, memahami hierarki class sangat penting untuk mengembangkan aplikasi Android dan memungkinkan Anda memanfaatkan fitur yang disediakan oleh framework Android.
Misalnya, ada class View
di Android yang mewakili area persegi panjang di layar dan bertanggung jawab menangani gambar dan peristiwa. Class TextView
adalah subclass dari class View
yang artinya TextView
mewarisi semua properti dan fungsi dari class View
, serta menambahkan logika khusus untuk menampilkan teks kepada pengguna.
Lebih jauh, class EditText
dan Button
adalah turunan dari class TextView
. Kedua class tersebut mewarisi semua properti dan metode class TextView
dan View
, serta menambahkan logika spesifiknya sendiri. Misalnya, EditText
menambahkan fungsinya sendiri untuk dapat mengedit teks di layar.
Daripada harus menyalin dan menempelkan semua logika dari class View
dan TextView
ke dalam class EditText
, EditText
hanya perlu membuat subclass dari class TextView
yang selanjutnya akan membuat subclass untuk class View
. Kemudian, kode dalam class EditText
dapat secara khusus berfokus pada perbedaan komponen UI ini dengan tampilan lainnya.
Di bagian atas halaman dokumentasi untuk class Android di situs developer.android.com, Anda dapat melihat diagram hierarki class. Anda akan dapat melihat kotlin.Any
di bagian atas hierarki karena di Kotlin, semua class memiliki superclass umum Any. Pelajari lebih lanjut di sini.
Seperti yang Anda lihat, mempelajari cara memanfaatkan pewarisan di antara class dapat membuat kode Anda lebih mudah ditulis, digunakan kembali, dibaca, dan diuji.
3. Membuat class dasar
Hierarki class tempat tinggal
Dalam codelab ini, Anda akan mem-build program Kotlin yang menunjukkan cara kerja hierarki class, menggunakan tempat tinggal (selter hunian) yang dilengkapi ruang lantai, tingkat, dan penghuni sebagai contoh.
Di bawah ini merupakan diagram hierarki class yang akan Anda buat. Di root, Anda memiliki Dwelling
yang menentukan properti dan fungsi yang berlaku untuk semua tempat tinggal, mirip dengan cetak biru. Anda juga akan memiliki class untuk kabin persegi (SquareCabin
), pondok bundar (RoundHut
), dan menara bundar (RoundTower
) yang merupakan RoundHut
dengan beberapa lantai.
Class yang akan diterapkan:
Dwelling
: class dasar yang mewakili selter non-spesifik yang menyimpan informasi umum untuk semua tempat tinggal.SquareCabin
: kabin persegi yang terbuat dari kayu dengan area lantai persegi.RoundHut
: pondok bundar yang terbuat dari jerami dengan area lantai melingkar, dan induk dariRoundTower
.RoundTower
: menara bundar yang terbuat dari batu dengan area lantai melingkar dan beberapa tingkat.
Membuat class Dwelling abstrak
Semua class dapat berupa class dasar dari hierarki class atau induk dari class lainnya.
Class "abstrak" adalah class yang tidak dapat dibuat instance-nya karena tidak diterapkan sepenuhnya. Anda bisa menganggapnya sebagai sketsa. Sketsa menggabungkan ide dan rencana akan sesuatu, tetapi tidak cukup informasi untuk membuatnya. Anda menggunakan sketsa (class abstrak) untuk membuat cetak biru (class) tempat Anda membuat instance objek yang sebenarnya.
Manfaat umum pembuatan superclass adalah untuk menampung properti dan fungsi yang sama untuk semua subclass-nya. Jika nilai properti dan implementasi fungsi tidak diketahui, buatlah abstrak class. Misalnya, Vegetables
memiliki banyak properti yang sama dengan semua sayuran, tetapi Anda tidak dapat membuat instance sayuran non-spesifik karena tidak tahu bentuk atau warnanya. Jadi, Vegetable
adalah class abstrak yang membebaskan subclass untuk menentukan detail spesifik setiap sayuran.
Deklarasi class abstrak dimulai dengan kata kunci abstract
.
Dwelling
akan menjadi class abstrak seperti Vegetable
. Contoh class tersebut akan berisi properti dan fungsi umum untuk banyak jenis tempat tinggal, tetapi nilai properti dan detail penerapan fungsi yang tepat tidak diketahui.
- Buka Kotlin Playground di https://developer.android.com/training/kotlinplayground.
- Di editor, hapus
println("Hello, world!")
di dalam fungsimain()
. - Lalu, tambahkan kode ini di bawah fungsi
main()
untuk membuat classabstract
yang disebutDwelling
.
abstract class Dwelling(){
}
Menambahkan properti bahan bangunan
Di class Dwelling
ini, Anda menentukan berbagai hal yang benar untuk semua tempat tinggal, meskipun hal tersebut mungkin berbeda untuk tempat tinggal lain. Semua tempat tinggal terbuat dari bahan bangunan.
- Di dalam
Dwelling
, buat variabelbuildingMaterial
jenisString
untuk mewakili bahan bangunan. Bahan bangunan tidak pernah akan berubah. Jadi, gunakanval
untuk menjadikannya sebagai variabel yang tidak dapat diubah.
val buildingMaterial: String
- Jalankan program Anda dan error ini akan muncul.
Property must be initialized or be abstract
Properti buildingMaterial
tidak memiliki nilai. Bahkan, Anda TIDAK dapat menilainya karena bangunan non-spesifik tidak dibuat dari sesuatu yang spesifik. Jadi, seperti yang ditunjukkan oleh pesan error, Anda dapat mengawali deklarasi buildingMaterial
dengan kata kunci abstract
untuk menunjukkan bahwa bahan bangunan tidak akan ditentukan di sini.
- Tambahkan kata kunci
abstract
ke dalam definisi variabel.
abstract val buildingMaterial: String
- Jalankan kode Anda, dan meskipun tidak melakukan apa pun, kode tersebut akan dikompilasi tanpa error.
- Buat instance
Dwelling
dalam fungsimain()
dan jalankan kode Anda.
val dwelling = Dwelling()
- Anda akan mendapatkan error karena Anda tidak dapat membuat instance class
Dwelling
abstrak.
Cannot create an instance of an abstract class
- Hapus kode yang salah ini.
Kode akhir Anda sejauh ini:
abstract class Dwelling(){
abstract val buildingMaterial: String
}
Menambahkan properti kapasitas
Properti lain dari tempat tinggal adalah kapasitas, yaitu jumlah orang yang dapat tinggal di dalamnya.
Semua tempat tinggal memiliki kapasitas yang tidak berubah. Namun, kapasitas tidak dapat ditetapkan dalam superclass Dwelling
. Kapasitas harus didefinisikan dalam subclass untuk jenis tempat tinggal tertentu.
- Dalam
Dwelling
, tambahkan bilangan bulatabstract
val
yang disebutcapacity
.
abstract val capacity: Int
Menambahkan properti pribadi untuk jumlah penghuni
Semua tempat tinggal akan memiliki jumlah residents
yang menghuni tempat tinggal (jumlahnya bisa kurang dari atau sama dengan capacity
). Jadi, tentukan properti residents
dalam superclass Dwelling
untuk semua subclass yang akan diwarisi dan digunakan.
- Anda dapat membuat parameter
residents
yang diteruskan ke konstruktor classDwelling
. Propertiresidents
adalahvar
karena jumlah penghuni dapat berubah setelah instance dibuat.
abstract class Dwelling(private var residents: Int) {
Perhatikan bahwa properti residents
ditandai dengan kata kunci private
. Private merupakan pengubah visibilitas di Kotlin yang berarti bahwa properti residents
hanya terlihat oleh (dan dapat digunakan di dalam) class ini. Kode ini tidak dapat diakses dari tempat lain dalam program Anda. Anda dapat menandai properti atau metode dengan kata kunci private. Sebaliknya, jika tidak ada pengubah visibilitas yang ditentukan, properti dan metode akan bersifat public
secara default dan dapat diakses dari bagian lain program Anda. Jumlah orang yang menghuni tempat tinggal biasanya merupakan informasi pribadi (dibandingkan dengan informasi bahan bangunan atau kapasitas bangunan) dan ini adalah keputusan yang wajar.
Dengan capacity
dari tempat tinggal dan jumlah residents
saat ini yang ditentukan, Anda dapat membuat fungsi hasRoom()
untuk menentukan ketersediaan ruang untuk penghuni lain dalam tempat tinggal. Anda dapat menentukan dan mengimplementasikan fungsi hasRoom()
dalam class Dwelling
karena penghitungan ketersediaan ruang menggunakan formula yang sama untuk semua tempat tinggal. Ada ruang di dalam Dwelling
jika jumlah residents
kurang dari capacity
, dan fungsi ini akan menampilkan true
atau false
berdasarkan perbandingan ini.
- Tambahkan fungsi
hasRoom()
ke classDwelling
.
fun hasRoom(): Boolean {
return residents < capacity
}
- Anda dapat menjalankan kode ini dan seharusnya tidak akan ada error. Kode belum melakukan apa pun yang tampak.
Kode yang sudah selesai akan terlihat seperti ini:
abstract class Dwelling(private var residents: Int) {
abstract val buildingMaterial: String
abstract val capacity: Int
fun hasRoom(): Boolean {
return residents < capacity
}
}
4. Membuat subclass
Membuat subclass SquareCabin
- Di bawah class
Dwelling
, buat class dengan namaSquareCabin
.
class SquareCabin
- Selanjutnya, Anda harus menunjukkan bahwa
SquareCabin
berkaitan denganDwelling
. Dalam kode, Anda ingin menunjukkan bahwaSquareCabin
diperluas dariDwelling
(atau merupakan subclass untukDwelling)
karenaSquareCabin
akan menyediakan implementasi untuk bagian abstrakDwelling
.
Tunjukkan hubungan pewarisan ini dengan menambahkan titik dua (:
) setelah nama class SquareCabin
, lalu diikuti dengan panggilan untuk menginisialisasi class induk Dwelling
. Jangan lupa tambahkan tanda kurung setelah nama class Dwelling
.
class SquareCabin : Dwelling()
- Saat memperluas dari superclass, Anda harus meneruskan parameter wajib yang diminta oleh superclass.
Dwelling
memerlukan jumlahresidents
sebagai input. Anda dapat meneruskan jumlah penghuni tetap seperti3
.
class SquareCabin : Dwelling(3)
Namun, Anda ingin program menjadi lebih fleksibel dan memungkinkan jumlah variabel penghuni untuk SquareCabins
. Oleh karena itu, buat parameter residents
dengan definisi class SquareCabin
. Jangan mendeklarasikan residents
sebagai val,
karena Anda menggunakan kembali properti yang sudah dinyatakan di class induk Dwelling
.
class SquareCabin(residents: Int) : Dwelling(residents)
- Jalankan kode.
- Ini akan menyebabkan error. Lihat:
Class 'SquareCabin' is not abstract and does not implement abstract base class member public abstract val buildingMaterial: String defined in Dwelling
Saat Anda mendeklarasikan fungsi dan variabel abstrak, deklarasi ini akan menyerupai promise yang Anda beri nilai dan implementasinya nanti. Untuk variabel, ini artinya setiap subclass dari class abstrak tersebut harus memberikan nilai. Untuk fungsi, ini artinya setiap subclass perlu menerapkan isi fungsi.
Dalam class Dwelling
, Anda menetapkan variabel abstract
buildingMaterial
. SquareCabin
adalah subclass dari Dwelling
sehingga harus memberikan nilai untuk buildingMaterial
. Gunakan kata kunci override
untuk menunjukkan bahwa properti ini telah ditetapkan di class induk dan akan diganti di class ini.
- Dalam class
SquareCabin
,override
propertibuildingMaterial
dan isi nilainya dengan"Wood"
. - Lakukan hal yang sama untuk
capacity
yang menyebutkan 6 penghuni dapat tinggal diSquareCabin
.
class SquareCabin(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Wood"
override val capacity = 6
}
Kode yang sudah selesai akan terlihat seperti ini.
abstract class Dwelling(private var residents: Int) {
abstract val buildingMaterial: String
abstract val capacity: Int
fun hasRoom(): Boolean {
return residents < capacity
}
}
class SquareCabin(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Wood"
override val capacity = 6
}
Untuk menguji kode Anda, buat instance SquareCabin
di dalam program.
Menggunakan SquareCabin
- Sisipkan fungsi
main()
kosong sebelum definisi classDwelling
danSquareCabin
.
fun main() {
}
abstract class Dwelling(private var residents: Int) {
...
}
class SquareCabin(residents: Int) : Dwelling(residents) {
...
}
- Dalam fungsi
main()
, buat instanceSquareCabin
bernamasquareCabin
dengan 6 penghuni. Tambahkan pernyataan cetak untuk bahan bangunan, kapasitas, dan fungsihasRoom()
.
fun main() {
val squareCabin = SquareCabin(6)
println("\nSquare Cabin\n============")
println("Capacity: ${squareCabin.capacity}")
println("Material: ${squareCabin.buildingMaterial}")
println("Has room? ${squareCabin.hasRoom()}")
}
Perhatikan bahwa fungsi hasRoom()
tidak ditentukan di class SquareCabin
, tetapi ditentukan di class Dwelling
. Karena SquareCabin
adalah subclass dari class Dwelling
, fungsi hasRoom()
diwarisi secara cuma-cuma. Fungsi hasRoom()
sekarang dapat dipanggil di semua instance SquareCabin
, seperti yang terlihat dalam cuplikan kode sebagai squareCabin.hasRoom()
.
- Jalankan kode Anda, dan kode tersebut akan mencetak perintah berikut ini:
Square Cabin ============ Capacity: 6 Material: Wood Has room? false
Anda membuat squareCabin
dengan 6
penghuni yang setara dengan capacity
sehingga hasRoom()
menampilkan false
. Anda dapat bereksperimen dengan menginisialisasi SquareCabin
dengan jumlah residents
yang lebih kecil, dan saat Anda menjalankan program lagi, hasRoom()
harus menampilkan true
.
Menggunakan with untuk menyederhanakan kode Anda
Dalam pernyataan println()
, setiap kali Anda mereferensikan properti atau fungsi squareCabin
, perhatikan bagaimana Anda mengulangi squareCabin.
Hal ini menjadi berulang-ulang dan dapat menjadi sumber error saat Anda menyalin dan menempelkan pernyataan cetak.
Saat Anda bekerja dengan instance class tertentu dan harus mengakses beberapa properti dan fungsi instance tersebut, Anda dapat mengucapkan "lakukan semua operasi berikut dengan objek instance ini" menggunakan pernyataan with
. Mulai dengan kata kunci with
, diikuti dengan nama instance dalam tanda kurung, lalu diikuti dengan tanda kurung kurawal yang berisi operasi yang ingin Anda lakukan.
with (instanceName) {
// all operations to do with instanceName
}
- Dalam fungsi
main()
, ubah pernyataan cetak untuk menggunakanwith
. - Hapus
squareCabin.
di laporan cetak.
with(squareCabin) {
println("\nSquare Cabin\n============")
println("Capacity: ${capacity}")
println("Material: ${buildingMaterial}")
println("Has room? ${hasRoom()}")
}
- Jalankan kode Anda lagi untuk memastikan kode berjalan tanpa error dan menampilkan output yang sama.
Square Cabin ============ Capacity: 6 Material: Wood Has room? false
Ini adalah kode lengkap Anda:
fun main() {
val squareCabin = SquareCabin(6)
with(squareCabin) {
println("\nSquare Cabin\n============")
println("Capacity: ${capacity}")
println("Material: ${buildingMaterial}")
println("Has room? ${hasRoom()}")
}
}
abstract class Dwelling(private var residents: Int) {
abstract val buildingMaterial: String
abstract val capacity: Int
fun hasRoom(): Boolean {
return residents < capacity
}
}
class SquareCabin(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Wood"
override val capacity = 6
}
Membuat subclass RoundHut
- Dengan cara yang sama seperti
SquareCabin
, tambahkan subclass lain,RoundHut
, keDwelling
. - Ganti
buildingMaterial
dan beri nilai"Straw"
. - Ganti
capacity
dan tetapkan ke 4.
class RoundHut(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Straw"
override val capacity = 4
}
- Di
main()
, buat instanceRoundHut
dengan 3 penghuni.
val roundHut = RoundHut(3)
- Tambahkan kode di bawah untuk mencetak informasi tentang
roundHut
.
with(roundHut) {
println("\nRound Hut\n=========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
}
- Jalankan kode Anda, dan output untuk seluruh program seharusnya akan seperti berikut:
Square Cabin ============ Capacity: 6 Material: Wood Has room? false Round Hut ========= Material: Straw Capacity: 4 Has room? true
Anda sekarang memiliki hierarki class yang terlihat seperti ini, dengan Dwelling
sebagai class root serta SquareCabin
dan RoundHut
sebagai subclass dari Dwelling
.
Membuat subclass RoundTower
Class terakhir dalam hierarki class ini adalah menara bundar. Anggap menara bundar sebagai pondok bulat yang terbuat dari batu dan memiliki banyak lantai. Jadi, Anda dapat membuat RoundTower
sebagai subclass dari RoundHut
.
- Buat class
RoundTower
yang merupakan subclass dariRoundHut
. Tambahkan parameterresidents
ke konstruktorRoundTower
, lalu teruskan parameter tersebut ke konstruktor superclassRoundHut
. - Ganti
buildingMaterial
menjadi"Stone"
. - Tetapkan
capacity
ke4
.
class RoundTower(residents: Int) : RoundHut(residents) {
override val buildingMaterial = "Stone"
override val capacity = 4
}
- Jalankan kode ini dan Anda akan mendapatkan pesan error.
This type is final, so it cannot be inherited from
Error ini berarti bahwa class RoundHut
tidak dapat dibuatkan subclass-nya (atau diwariskan). Secara default, di Kotlin, class bersifat final dan tidak dapat dibuatkan subclass-nya. Anda hanya diizinkan untuk mewarisi dari class abstract
atau class yang ditandai dengan kata kunci open
. Oleh karena itu, Anda harus menandai class RoundHut
dengan kata kunci open
agar dapat diwariskan.
- Tambahkan kata kunci
open
di awal deklarasiRoundHut
.
open class RoundHut(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Straw"
override val capacity = 4
}
- Di
main()
, buat instanceroundTower
dan cetak informasinya.
val roundTower = RoundTower(4)
with(roundTower) {
println("\nRound Tower\n==========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
}
Kode lengkapnya sebagai berikut.
fun main() {
val squareCabin = SquareCabin(6)
val roundHut = RoundHut(3)
val roundTower = RoundTower(4)
with(squareCabin) {
println("\nSquare Cabin\n============")
println("Capacity: ${capacity}")
println("Material: ${buildingMaterial}")
println("Has room? ${hasRoom()}")
}
with(roundHut) {
println("\nRound Hut\n=========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
}
with(roundTower) {
println("\nRound Tower\n==========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
}
}
abstract class Dwelling(private var residents: Int) {
abstract val buildingMaterial: String
abstract val capacity: Int
fun hasRoom(): Boolean {
return residents < capacity
}
}
class SquareCabin(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Wood"
override val capacity = 6
}
open class RoundHut(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Straw"
override val capacity = 4
}
class RoundTower(residents: Int) : RoundHut(residents) {
override val buildingMaterial = "Stone"
override val capacity = 4
}
- Jalankan kode. Seharusnya sekarang kode dapat berfungsi tanpa error dan menghasilkan output berikut.
Square Cabin ============ Capacity: 6 Material: Wood Has room? false Round Hut ========= Material: Straw Capacity: 4 Has room? true Round Tower ========== Material: Stone Capacity: 4 Has room? false
Menambahkan beberapa lantai ke RoundTower
Berdasarkan implikasinya, RoundHut
merupakan bangunan satu lantai. Menara biasanya memiliki beberapa tingkat (lantai).
Dengan mempertimbangkan kapasitas, makin banyak lantai yang dimiliki sebuah menara, makin besar kapasitas yang seharusnya dimiliki.
Anda dapat mengubah RoundTower
agar memiliki beberapa lantai dan menyesuaikan kapasitasnya berdasarkan jumlah lantai.
- Perbarui konstruktor
RoundTower
untuk mengambil parameter bilangan bulat tambahanval floors
untuk jumlah lantai. Tempatkan setelahresidents
. Perhatikan bahwa Anda tidak perlu meneruskan ini ke konstruktorRoundHut
induk karenafloors
ditentukan di sini dalamRoundTower
danRoundHut
tidak memilikifloors
.
class RoundTower(
residents: Int,
val floors: Int) : RoundHut(residents) {
...
}
- Jalankan kode. Terjadi error saat membuat
roundTower
dalam metodemain()
karena Anda tidak memberikan angka untuk argumenfloors
. Anda dapat menambahkan argumen yang tidak ada.
Atau, dalam definisi class RoundTower
, Anda dapat menambahkan nilai default untuk floors
seperti yang ditunjukkan di bawah ini. Kemudian, jika tidak ada nilai untuk floors
yang diteruskan ke dalam konstruktor, nilai default dapat digunakan untuk membuat instance objek.
- Dalam kode Anda, tambahkan
= 2
setelah pernyataanfloors
untuk menetapkan nilai default 2.
class RoundTower(
residents: Int,
val floors: Int = 2) : RoundHut(residents) {
...
}
- Jalankan kode. Kode harus dikompilasi karena
RoundTower(4)
sekarang membuat instance objekRoundTower
dengan nilai default 2 lantai. - Di class
RoundTower
, perbaruicapacity
untuk mengalikannya dengan jumlah lantai.
override val capacity = 4 * floors
- Jalankan kode Anda dan perhatikan bahwa kapasitas
RoundTower
sekarang menjadi 8 untuk 2 lantai.
Berikut adalah kode yang sudah selesai.
fun main() {
val squareCabin = SquareCabin(6)
val roundHut = RoundHut(3)
val roundTower = RoundTower(4)
with(squareCabin) {
println("\nSquare Cabin\n============")
println("Capacity: ${capacity}")
println("Material: ${buildingMaterial}")
println("Has room? ${hasRoom()}")
}
with(roundHut) {
println("\nRound Hut\n=========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
}
with(roundTower) {
println("\nRound Tower\n==========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
}
}
abstract class Dwelling(private var residents: Int) {
abstract val buildingMaterial: String
abstract val capacity: Int
fun hasRoom(): Boolean {
return residents < capacity
}
}
class SquareCabin(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Wood"
override val capacity = 6
}
open class RoundHut(residents: Int) : Dwelling(residents) {
override val buildingMaterial = "Straw"
override val capacity = 4
}
class RoundTower(
residents: Int,
val floors: Int = 2) : RoundHut(residents) {
override val buildingMaterial = "Stone"
override val capacity = 4 * floors
}
5. Mengubah class dalam hierarki
Menghitung luas lantai
Dalam latihan ini, Anda akan mempelajari cara mendeklarasikan fungsi abstrak di class abstrak, lalu menerapkan fungsinya di subclass.
Semua tempat tinggal memiliki luas lantai, tetapi penghitungannya berbeda-beda menyesuaikan bentuk tempat tinggal.
Menentukan floorArea() di class Dwelling
- Pertama-tama, tambahkan fungsi
abstract
floorArea()
ke classDwelling
. TampilkanDouble
. Double adalah jenis data, sepertiString
danInt
; data ini digunakan untuk bilangan floating point, yaitu bilangan yang memiliki titik desimal yang diikuti oleh bagian pecahan, seperti 5,8793.
abstract fun floorArea(): Double
Semua metode abstrak yang didefinisikan dalam class abstrak harus diterapkan di salah satu subclass-nya. Sebelum dapat menjalankan kode, Anda perlu mengimplementasikan floorArea()
di subclass.
Mengimplementasikan floorArea() untuk SquareCabin
Seperti pada buildingMaterial
dan capacity
, karena mengimplementasikan fungsi abstract
yang ditentukan di class induk, Anda harus menggunakan kata kunci override
.
- Di class
SquareCabin
, mulai dengan kata kuncioverride
lalu diikuti dengan penerapan fungsifloorArea()
yang sebenarnya seperti yang ditunjukkan di bawah ini.
override fun floorArea(): Double {
}
- Tampilkan luas lantai yang dihitung. Luas persegi panjang atau persegi adalah panjang sisi yang dikalikan dengan panjang sisi lainnya. Isi fungsinya adalah
return length * length
.
override fun floorArea(): Double {
return length * length
}
Panjang ini bukanlah variabel dalam class dan berbeda untuk setiap instance sehingga Anda dapat menambahkannya sebagai parameter konstruktor untuk class SquareCabin
.
- Ubah definisi class
SquareCabin
untuk menambahkan parameterlength
jenisDouble
. Nyatakan properti sebagaival
karena panjang bangunan tidak berubah.
class SquareCabin(residents: Int, val length: Double) : Dwelling(residents) {
Dwelling
dan semua subclass-nya memiliki residents
sebagai argumen konstruktor. Argumen tersebut merupakan argumen pertama dalam konstruktor Dwelling
. Jadi, sebaiknya Anda juga menjadikannya sebagai argumen pertama di semua konstruktor subclass dan menempatkan argumen dalam urutan yang sama di semua definisi class. Oleh karena itu, masukkan parameter length
baru setelah parameter residents
.
- Dalam
main()
, perbarui pembuatan instancesquareCabin
. Teruskan50.0
ke konstruktorSquareCabin
sebagailength
.
val squareCabin = SquareCabin(6, 50.0)
- Dalam pernyataan
with
untuksquareCabin
, tambahkan pernyataan cetak untuk luas lantai.
println("Floor area: ${floorArea()}")
Kode tidak akan berjalan karena Anda juga harus mengimplementasikan floorArea()
dalam RoundHut
.
Mengimplementasikan floorArea() untuk RoundHut
Dengan cara yang sama, implementasikan luas lantai untuk RoundHut
. RoundHut
juga merupakan subclass langsung dari Dwelling
sehingga Anda harus menggunakan kata kunci override
.
Luas lantai tempat tinggal melingkar adalah PI * radius * radius.
PI
adalah nilai matematika. Nilai ini ditentukan dalam library matematika. Library adalah kumpulan fungsi dan nilai yang telah ditentukan sebelumnya dan ditetapkan di luar program yang dapat digunakan oleh program. Untuk menggunakan fungsi atau nilai library, Anda harus memberi tahu compiler bahwa Anda akan menggunakannya. Anda melakukannya dengan mengimpor fungsi atau nilai ke dalam program. Untuk menggunakan PI
dalam program, Anda perlu mengimpor kotlin.math.PI
.
- Impor
PI
dari library matematika Kotlin. Letakkan ini di bagian atas file, sebelummain()
.
import kotlin.math.PI
- Implementasikan fungsi
floorArea()
untukRoundHut
.
override fun floorArea(): Double {
return PI * radius * radius
}
Peringatan: Jika tidak mengimpor kotlin.math.PI, Anda akan mendapatkan error, jadi impor library ini sebelum menggunakannya. Atau, Anda dapat menulis versi PI yang sepenuhnya memenuhi syarat, seperti dalam kotlin.math.PI * radius * radius, dan kemudian pernyataan impor tidak diperlukan.
- Perbarui konstruktor
RoundHut
untuk memasukkanradius
.
open class RoundHut(
residents: Int,
val radius: Double) : Dwelling(residents) {
- Dalam
main()
, perbarui inisialisasiroundHut
dengan meneruskanradius
dari10.0
ke konstruktorRoundHut
.
val roundHut = RoundHut(3, 10.0)
- Tambahkan pernyataan cetak di dalam pernyataan
with
untukroundHut
.
println("Floor area: ${floorArea()}")
Mengimplementasikan floorArea() untuk RoundTower
Kode Anda belum berjalan, dan gagal dengan menampilkan error ini:
Error: No value passed for parameter 'radius'
Dalam RoundTower
, agar program dapat dikompilasi, Anda tidak perlu mengimplementasikan floorArea()
karena akan diwarisi dari RoundHut
, tetapi Anda perlu memperbarui definisi class RoundTower
agar memiliki argumen radius
yang sama dengan induknya, RoundHut
.
- Ubah konstruktor RoundTower untuk menggunakan
radius
. Masukkanradius
setelahresidents
dan sebelumfloors
. Sebaiknya variabel dengan nilai default dicantumkan di bagian akhir. Jangan lupa meneruskanradius
ke konstruktor class induk.
class RoundTower(
residents: Int,
radius: Double,
val floors: Int = 2) : RoundHut(residents, radius) {
- Perbarui inisialisasi
roundTower
dimain()
.
val roundTower = RoundTower(4, 15.5)
- Dan tambahkan pernyataan cetak yang memanggil
floorArea()
.
println("Floor area: ${floorArea()}")
- Sekarang Anda sudah dapat menjalankan kode!
- Perhatikan bahwa penghitungan untuk
RoundTower
tidak benar karena diwarisi dariRoundHut
dan tidak memperhitungkan jumlahfloors
. - Di dalam
RoundTower
, lakukanoverride floorArea()
agar dapat memberikan penerapan berbeda yang mengalikan luas dengan jumlah lantai. Perhatikan bahwa Anda dapat menentukan fungsi dalam class abstrak (Dwelling
), menerapkannya dalam subclass (RoundHut
), lalu menggantinya lagi dalam subclass dari subclass (RoundTower
). Ini adalah cara terbaik untuk keduanya karena Anda mewarisi fungsi yang diinginkan dan dapat mengganti fungsi yang tidak diinginkan.
override fun floorArea(): Double {
return PI * radius * radius * floors
}
Kode ini berfungsi, tetapi ada cara untuk menghindari pengulangan kode yang sudah ada di class induk RoundHut
. Anda dapat memanggil fungsi floorArea()
dari class RoundHut
induk, yang menampilkan PI * radius * radius
. Lalu, kalikan hasil tersebut dengan jumlah floors
.
- Dalam
RoundTower
, perbaruifloorArea()
untuk menggunakan implementasi superclassfloorArea()
. Gunakan kata kuncisuper
untuk memanggil fungsi yang ditentukan di induk.
override fun floorArea(): Double {
return super.floorArea() * floors
}
- Jalankan lagi kode Anda dan
RoundTower
menghasilkan ruang lantai yang benar untuk beberapa lantai.
Berikut adalah kode yang sudah selesai:
import kotlin.math.PI
fun main() {
val squareCabin = SquareCabin(6, 50.0)
val roundHut = RoundHut(3, 10.0)
val roundTower = RoundTower(4, 15.5)
with(squareCabin) {
println("\nSquare Cabin\n============")
println("Capacity: ${capacity}")
println("Material: ${buildingMaterial}")
println("Has room? ${hasRoom()}")
println("Floor area: ${floorArea()}")
}
with(roundHut) {
println("\nRound Hut\n=========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
println("Floor area: ${floorArea()}")
}
with(roundTower) {
println("\nRound Tower\n==========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Has room? ${hasRoom()}")
println("Floor area: ${floorArea()}")
}
}
abstract class Dwelling(private var residents: Int) {
abstract val buildingMaterial: String
abstract val capacity: Int
fun hasRoom(): Boolean {
return residents < capacity
}
abstract fun floorArea(): Double
}
class SquareCabin(residents: Int,
val length: Double) : Dwelling(residents) {
override val buildingMaterial = "Wood"
override val capacity = 6
override fun floorArea(): Double {
return length * length
}
}
open class RoundHut(residents: Int,
val radius: Double) : Dwelling(residents) {
override val buildingMaterial = "Straw"
override val capacity = 4
override fun floorArea(): Double {
return PI * radius * radius
}
}
class RoundTower(residents: Int, radius: Double,
val floors: Int = 2) : RoundHut(residents, radius) {
override val buildingMaterial = "Stone"
override val capacity = 4 * floors
override fun floorArea(): Double {
return super.floorArea() * floors
}
}
Output harus berupa:
Square Cabin ============ Capacity: 6 Material: Wood Has room? false Floor area: 2500.0 Round Hut ========= Material: Straw Capacity: 4 Has room? true Floor area: 314.1592653589793 Round Tower ========== Material: Stone Capacity: 8 Has room? true Floor area: 1509.5352700498956
Memungkinkan penghuni baru mendapatkan ruangan
Tambahkan kemampuan bagi penghuni baru agar mendapatkan ruangan dengan fungsi getRoom()
yang akan meningkatkan jumlah penghuni sebanyak satu. Logika ini sama untuk semua tempat tinggal sehingga Anda dapat mengimplementasikan fungsi di Dwelling
, dan logika akan tersedia untuk semua subclass dan turunannya. Keren!
Catatan:
- Gunakan pernyataan
if
yang hanya akan menambahkan satu penghuni jika kapasitas tersisa. - Cetak pesan untuk mendapatkan hasilnya.
- Anda dapat menggunakan
residents++
sebagai singkatanresidents = residents + 1
untuk menambahkan 1 ke variabelresidents
.
- Implementasikan fungsi
getRoom()
di classDwelling
.
fun getRoom() {
if (capacity > residents) {
residents++
println("You got a room!")
} else {
println("Sorry, at capacity and no rooms left.")
}
}
- Tambahkan beberapa pernyataan cetak ke blok pernyataan
with
untukroundHut
guna mengamati proses yang akan terjadi jikagetRoom()
danhasRoom()
digunakan bersamaan.
println("Has room? ${hasRoom()}")
getRoom()
println("Has room? ${hasRoom()}")
getRoom()
Output untuk pernyataan cetak ini:
Has room? true You got a room! Has room? false Sorry, at capacity and no rooms left.
Lihat Kode solusi untuk mengetahui detailnya.
Memasang karpet ke dalam tempat tinggal bundar
Misalnya Anda perlu mengetahui panjang satu sisi karpet yang harus digunakan untuk RoundHut
atau RoundTower
. Masukkan fungsi ke dalam RoundHut
untuk menyediakannya ke semua tempat tinggal bundar.
- Impor terlebih dahulu fungsi
sqrt()
dari librarykotlin.math
.
import kotlin.math.sqrt
- Implementasikan fungsi
calculateMaxCarpetLength()
di classRoundHut
. Formula untuk menghitung panjang karpet persegi yang dapat pas dalam lingkaran adalahsqrt(2) * radius
. Hal ini dijelaskan dalam diagram di atas.
fun calculateMaxCarpetLength(): Double {
return sqrt(2.0) * radius
}
Teruskan nilai Double
, 2.0
ke fungsi matematika sqrt(2.0)
, karena jenis nilai fungsi yang ditampilkan adalah Double
, bukan Integer
.
- Sekarang metode
calculateMaxCarpetLength()
dapat dipanggil pada instanceRoundHut
danRoundTower
. Tambahkan pernyataan cetak keroundHut
danroundTower
dalam fungsimain()
.
println("Carpet Length: ${calculateMaxCarpetLength()}")
Lihat Kode solusi untuk mengetahui detailnya.
Selamat! Anda telah membuat hierarki class lengkap dengan properti dan fungsi, serta mempelajari semua yang Anda butuhkan untuk membuat class yang lebih bermanfaat.
6. Kode solusi
Kode solusi lengkap di bawah untuk codelab ini, termasuk komentar.
/**
* Program that implements classes for different kinds of dwellings.
* Shows how to:
* Create class hierarchy, variables and functions with inheritance,
* abstract class, overriding, and private vs. public variables.
*/
import kotlin.math.PI
import kotlin.math.sqrt
fun main() {
val squareCabin = SquareCabin(6, 50.0)
val roundHut = RoundHut(3, 10.0)
val roundTower = RoundTower(4, 15.5)
with(squareCabin) {
println("\nSquare Cabin\n============")
println("Capacity: ${capacity}")
println("Material: ${buildingMaterial}")
println("Floor area: ${floorArea()}")
}
with(roundHut) {
println("\nRound Hut\n=========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Floor area: ${floorArea()}")
println("Has room? ${hasRoom()}")
getRoom()
println("Has room? ${hasRoom()}")
getRoom()
println("Carpet size: ${calculateMaxCarpetLength()}")
}
with(roundTower) {
println("\nRound Tower\n==========")
println("Material: ${buildingMaterial}")
println("Capacity: ${capacity}")
println("Floor area: ${floorArea()}")
println("Carpet Length: ${calculateMaxCarpetLength()}")
}
}
/**
* Defines properties common to all dwellings.
* All dwellings have floorspace,
* but its calculation is specific to the subclass.
* Checking and getting a room are implemented here
* because they are the same for all Dwelling subclasses.
*
* @param residents Current number of residents
*/
abstract class Dwelling(private var residents: Int) {
abstract val buildingMaterial: String
abstract val capacity: Int
/**
* Calculates the floor area of the dwelling.
* Implemented by subclasses where shape is determined.
*
* @return floor area
*/
abstract fun floorArea(): Double
/**
* Checks whether there is room for another resident.
*
* @return true if room available, false otherwise
*/
fun hasRoom(): Boolean {
return residents < capacity
}
/**
* Compares the capacity to the number of residents and
* if capacity is larger than number of residents,
* add resident by increasing the number of residents.
* Print the result.
*/
fun getRoom() {
if (capacity > residents) {
residents++
println("You got a room!")
} else {
println("Sorry, at capacity and no rooms left.")
}
}
}
/**
* A square cabin dwelling.
*
* @param residents Current number of residents
* @param length Length
*/
class SquareCabin(residents: Int, val length: Double) : Dwelling(residents) {
override val buildingMaterial = "Wood"
override val capacity = 6
/**
* Calculates floor area for a square dwelling.
*
* @return floor area
*/
override fun floorArea(): Double {
return length * length
}
}
/**
* Dwelling with a circular floorspace
*
* @param residents Current number of residents
* @param radius Radius
*/
open class RoundHut(
residents: Int, val radius: Double) : Dwelling(residents) {
override val buildingMaterial = "Straw"
override val capacity = 4
/**
* Calculates floor area for a round dwelling.
*
* @return floor area
*/
override fun floorArea(): Double {
return PI * radius * radius
}
/**
* Calculates the max length for a square carpet
* that fits the circular floor.
*
* @return length of square carpet
*/
fun calculateMaxCarpetLength(): Double {
return sqrt(2.0) * radius
}
}
/**
* Round tower with multiple stories.
*
* @param residents Current number of residents
* @param radius Radius
* @param floors Number of stories
*/
class RoundTower(
residents: Int,
radius: Double,
val floors: Int = 2) : RoundHut(residents, radius) {
override val buildingMaterial = "Stone"
// Capacity depends on the number of floors.
override val capacity = floors * 4
/**
* Calculates the total floor area for a tower dwelling
* with multiple stories.
*
* @return floor area
*/
override fun floorArea(): Double {
return super.floorArea() * floors
}
}
7. Ringkasan
Dalam codelab ini, Anda telah mempelajari cara:
- Membuat hierarki class, yaitu pohon class tempat turunan mewarisi fungsi dari class induk. Properti dan fungsi diwarisi oleh subclass.
- Membuat class
abstract
tempat beberapa fungsi dibiarkan untuk diimplementasikan oleh subclass-nya. Oleh karena itu, instance untuk classabstract
tidak dapat dibuat. - Membuat subclass dari class
abstract
. - Menggunakan kata kunci
override
untuk mengganti properti dan fungsi di subclass. - Menggunakan kata kunci
super
untuk mereferensikan fungsi dan properti di class induk. - Membuat class
open
agar dapat dibuatkan subclass-nya. - Membuat properti
private
agar hanya dapat digunakan di dalam class. - Menggunakan konstruksi
with
untuk melakukan beberapa panggilan pada instance objek yang sama. - Mengimpor fungsi dari library
kotlin.math