Buku “Head First. Kotlin »

gambar Hai, habrozhiteli! Kami memiliki buku yang diterbitkan untuk mempelajari Kotlin menggunakan teknik Kepala Pertama, yang melampaui sintaks dan instruksi untuk memecahkan masalah tertentu. Buku ini akan memberi Anda semua yang Anda butuhkan - mulai dari dasar-dasar bahasa hingga metode lanjutan. Dan Anda dapat berlatih pemrograman berorientasi objek dan fungsional.

Kutipan "Kelas Data" disajikan di bawah potongan.

Bekerja dengan data


Tidak ada yang mau membuang waktu dan mengulang apa yang sudah dilakukan. Sebagian besar aplikasi menggunakan kelas untuk menyimpan data. Untuk mempermudah pekerjaan, pencipta Kotlin mengusulkan konsep kelas data. Dalam bab ini, Anda akan belajar bagaimana kelas data membantu Anda menulis kode yang lebih elegan dan ringkas yang hanya bisa Anda impikan sebelumnya. Kami akan melihat fungsi pembantu kelas data dan belajar bagaimana menguraikan objek data menjadi komponen. Pada saat yang sama, kami akan menjelaskan bagaimana nilai parameter default membuat kode lebih fleksibel, dan juga memperkenalkan Anda kepada Any, leluhur semua superclasses.

Operator == memanggil fungsi yang disebut sama dengan


Seperti yang sudah Anda ketahui, operator == dapat digunakan untuk memverifikasi kesetaraan. Setiap kali pernyataan == dieksekusi, fungsi yang disebut equals dipanggil. Setiap objek berisi fungsi sama dengan, dan penerapan fungsi ini menentukan perilaku operator ==.

Secara default, fungsi sama dengan untuk memeriksa kesetaraan memeriksa apakah dua referensi variabel ke objek yang sama.

Untuk memahami cara kerjanya, bayangkan dua variabel Wolf bernama w1 dan w2. Jika w1 dan w2 berisi referensi ke satu objek Wolf, ketika membandingkannya dengan operator ==, hasilnya benar:

gambar

Tetapi jika w1 dan w2 berisi referensi ke objek Wolf yang berbeda, membandingkannya dengan operator == memberikan hasil yang salah, bahkan jika objek tersebut berisi nilai properti yang sama.

gambar

Seperti disebutkan sebelumnya, fungsi equals secara otomatis termasuk dalam setiap objek yang Anda buat. Tapi dari mana fungsi ini berasal?

sama dengan warisan dari superclass Any


Setiap objek berisi fungsi yang disebut equals karena kelasnya mewarisi fungsi dari kelas bernama Any. Kelas Any adalah leluhur semua kelas: superclass yang dihasilkan dari segalanya. Setiap kelas yang Anda tetapkan adalah subkelas Any, dan Anda tidak perlu menunjukkan ini dalam program. Jadi, jika Anda menulis kode kelas yang disebut myClass, yang terlihat seperti ini:

class MyClass { ... } 

Kompiler akan secara otomatis mengonversinya ke bentuk berikut:
gambar

Setiap kelas adalah subkelas Any dan mewarisi perilakunya. Setiap kelas adalah subkelas Any, dan Anda tidak harus melaporkan ini dalam program.

Pentingnya Warisan Apa Pun


Termasuk Any sebagai superclass yang dihasilkan memiliki dua keunggulan penting:

  • Ini memastikan bahwa setiap kelas mewarisi perilaku umum. Kelas Apa pun mendefinisikan perilaku penting yang menjadi sandaran operasi sistem. Dan karena setiap kelas adalah subkelas Any, perilaku ini diwarisi oleh semua objek yang Anda buat. Jadi, kelas Any mendefinisikan fungsi yang disebut equals, dan oleh karena itu, fungsi ini secara otomatis diwarisi oleh semua objek.
  • Ini berarti bahwa polimorfisme dapat digunakan dengan benda apa pun. Setiap kelas adalah subkelas Any, jadi objek apa pun yang Anda buat memiliki kelas Any sebagai supertype terakhirnya. Ini berarti bahwa Anda dapat membuat fungsi dengan parameter apa pun atau tipe pengembalian apa pun yang akan berfungsi dengan objek jenis apa pun. Ini juga berarti bahwa Anda dapat membuat array polimorfik untuk menyimpan objek jenis apa pun dengan kode dari formulir berikut:

 val myArray = arrayOf(Car(), Guitar(), Giraffe()) 

Kompiler memperhatikan bahwa setiap objek dalam array memiliki prototipe umum Any, dan karenanya membuat array bertipe Array.

Perilaku umum yang diwarisi oleh kelas Apa pun layak untuk dilihat lebih dekat.

Perilaku umum yang diwarisi dari Any


Kelas Any mendefinisikan beberapa fungsi yang diwarisi oleh masing-masing kelas. Berikut adalah contoh fungsi dasar dan perilakunya:

  • sama dengan (apa saja: Apa saja): Boolean
    Periksa apakah dua objek dianggap "sama". Secara default, fungsi mengembalikan true jika digunakan untuk memeriksa satu objek, atau salah - untuk objek yang berbeda. Di belakang layar, fungsi equals dipanggil setiap kali operator == digunakan dalam program.

 val w1 = Wolf() val w1 = Wolf() val w2 = Wolf() val w2 = w1 println(w1.equals(w2)) println(w1.equals(w2)) false (equals  false, true (equals  true,   w1  w2   w1  w2        .)      —   ,   w1 == w2. 

  • hashCode (): Int
    Mengembalikan kode hash untuk objek. Kode hash sering digunakan oleh beberapa struktur data untuk secara efisien menyimpan dan mengambil nilai.

 val w = Wolf() println(w.hashCode()) 

523429237 (Nilai kode hash w)

  • toString (): String
    Mengembalikan pesan String yang mewakili objek. Secara default, pesan berisi nama kelas dan nomor, yang biasanya tidak kita pedulikan.

 val w = Wolf() println(w.toString()) 

Serigala @ 1f32e575

Secara default, fungsi sama dengan memeriksa apakah dua objek adalah objek aktual yang sama.

Fungsi equals menentukan perilaku operator ==.

Kelas Apa pun menyediakan implementasi default untuk semua fungsi yang terdaftar, dan implementasi ini diwarisi oleh semua kelas. Namun, Anda dapat mengganti implementasi ini untuk mengubah perilaku default semua fungsi yang terdaftar.

Pemeriksaan kesetaraan sederhana dari dua objek


Dalam beberapa situasi, Anda perlu mengubah implementasi fungsi equals untuk mengubah perilaku operator ==.

Misalkan Anda memiliki kelas Resep yang memungkinkan Anda membuat objek untuk menyimpan resep. Dalam situasi seperti itu, Anda cenderung menganggap dua objek Resep sama (atau setara) jika berisi deskripsi resep yang sama. Katakanlah kelas Resep didefinisikan dengan dua properti - title dan isVegetarian:

 class Recipe(val title: String, val isVegetarian: Boolean) { } 

Operator == akan mengembalikan true jika digunakan untuk membandingkan dua objek Resep dengan properti, judul dan isVegetarian yang sama:

 val r1 = Recipe("Chicken Bhuna", false) val r2 = Recipe("Chicken Bhuna", false) 

gambar

Meskipun Anda dapat mengubah perilaku operator == dengan menulis kode tambahan untuk mengganti fungsi equals, pengembang Kotlin telah memberikan solusi yang lebih nyaman: mereka menciptakan konsep kelas data. Mari kita lihat apa kelas-kelas ini dan bagaimana mereka dibuat.

Kelas data memungkinkan Anda untuk membuat objek data.


Kelas data adalah kelas untuk membuat objek untuk menyimpan data. Ini termasuk alat yang berguna untuk bekerja dengan data - misalnya, implementasi baru dari fungsi equals, yang memeriksa apakah dua objek data berisi nilai properti yang sama. Jika dua objek berisi data yang sama, maka keduanya dapat dianggap sama.

Untuk menentukan kelas data, awali definisi data biasa dengan kata kunci data. Kode berikut mengonversi kelas Resep yang dibuat sebelumnya ke kelas data:

 data class Recipe(val title: String, val isVegetarian: Boolean) { } 

Awalan data mengonversi kelas reguler ke kelas data.

Cara membuat objek berdasarkan kelas data


Objek kelas data dibuat dengan cara yang sama dengan objek kelas biasa: dengan memanggil konstruktor dari kelas ini. Misalnya, kode berikut membuat objek data Resep baru dan menetapkannya ke variabel baru bernama r1:

 val r1 = Recipe("Chicken Bhuna", false) 

Kelas data secara otomatis mengesampingkan fungsinya yang sama untuk mengubah perilaku operator == sehingga kesetaraan objek diperiksa berdasarkan nilai properti dari setiap objek. Jika, misalnya, Anda membuat dua objek Resep dengan nilai properti yang sama, membandingkan kedua objek dengan operator == akan memberikan hasil yang benar, karena data yang sama disimpan di dalamnya:

 val r1 = Recipe("Chicken Bhuna", false) val r2 = Recipe("Chicken Bhuna", false) //r1 == r2  true 

r1 dan r2 dianggap "sama" karena dua objek Recipe berisi data yang sama.

Selain implementasi baru dari fungsi sama yang diwarisi dari superclass Any, kelas data
juga menimpa hashCode dan fungsi toString. Mari kita lihat bagaimana fungsi-fungsi ini diimplementasikan.

Objek kelas mendefinisikan kembali perilaku bawaan mereka


Untuk bekerja dengan data, kelas data memerlukan objek, oleh karena itu ia secara otomatis menyediakan implementasi berikut untuk fungsi equals, hashCode dan toString yang diwarisi dari Any superclass:

Fungsi equals membandingkan nilai properti


Ketika mendefinisikan kelas data, fungsinya sama dengan (dan karenanya operator ==) masih mengembalikan true jika tautan menunjuk ke objek yang sama. Tapi itu juga mengembalikan true jika objek memiliki nilai properti yang sama didefinisikan dalam konstruktor:

 val r1 = Recipe("Chicken Bhuna", false) val r2 = Recipe("Chicken Bhuna", false) println(r1.equals(r2)) true 

Objek data dianggap sama jika propertinya mengandung nilai yang sama.

Untuk objek yang sama, nilai kode hash yang sama dikembalikan


Jika dua objek data dianggap sama (dengan kata lain, mereka memiliki nilai properti yang sama), fungsi kode hash mengembalikan nilai yang sama untuk objek-objek ini:

 val r1 = Recipe("Chicken Bhuna", false) val r2 = Recipe("Chicken Bhuna", false) println(r1.hashCode()) println(r2.hashCode()) 

241131113
241131113

toString mengembalikan nilai semua properti


Akhirnya, fungsi toString tidak lagi mengembalikan nama kelas, diikuti oleh angka, tetapi mengembalikan string yang berguna dengan nilai-nilai semua properti yang didefinisikan dalam konstruktor kelas data:

 val r1 = Recipe("Chicken Bhuna", false) println(r1.toString()) Recipe(title=Chicken Bhuna, isVegetarian=false) 

Selain fungsi-fungsi utama yang diwarisi dari Any superclass, kelas data juga menyediakan alat tambahan yang menyediakan pekerjaan yang lebih efisien dengan data, misalnya, kemampuan untuk menyalin objek data. Mari kita lihat bagaimana alat ini bekerja.

Menyalin objek data dengan fungsi salin


Jika Anda perlu membuat salinan objek data dengan mengubah beberapa propertinya, tetapi membiarkan properti lain dalam keadaan aslinya, gunakan fungsi salin. Untuk melakukan ini, fungsi dipanggil untuk objek yang ingin Anda salin, dan nama-nama semua properti yang bisa berubah dengan nilai baru diteruskan ke sana.

Misalkan Anda memiliki objek Resep bernama r1, yang didefinisikan dalam kode seperti ini:

 val r1 = Recipe("Thai Curry", false) 

gambar

Jika Anda ingin membuat salinan objek Recipe, mengganti nilai properti isVegetarian dengan true, ini dilakukan seperti ini:

gambar

Pada dasarnya, ini berarti "membuat salinan objek r1, mengubah nilai properti isVegetarian menjadi true, dan menetapkan objek baru ke variabel bernama r2." Ini menciptakan salinan baru dari objek, dan objek asli tetap tidak berubah.

Selain fungsi penyalinan, kelas data juga menyediakan satu set fungsi untuk memisahkan objek data menjadi satu set nilai dari propertinya - proses ini disebut merusak. Mari kita lihat bagaimana ini dilakukan.

Kelas data mendefinisikan fungsi komponenN ...


Ketika mendefinisikan kelas data, kompiler secara otomatis menambah kelas serangkaian fungsi yang dapat digunakan sebagai mekanisme alternatif untuk mengakses nilai properti objek. Fungsi-fungsi ini dikenal dengan nama umum fungsi componentN, di mana N adalah jumlah properti yang akan diambil (dalam urutan deklarasi).

Untuk melihat bagaimana fungsi componentN bekerja, misalkan Anda memiliki objek Resep berikut:

 val r = Recipe("Chicken Bhuna", false) 

Jika Anda ingin mendapatkan nilai properti pertama objek (properti judul), Anda dapat memanggil fungsi component1 () objek untuk ini:

 val title = r.component1() 

component1 () mengembalikan referensi yang terkandung dalam properti pertama yang didefinisikan dalam konstruktor kelas data.

Fungsi melakukan hal yang sama seperti kode berikut:

 val title = r.title 

Kode dengan fungsi lebih universal. Mengapa fungsi ComponentN sangat berguna di kelas data?

... dirancang untuk merestrukturisasi objek data


Fungsi komponen N generik berguna terutama karena mereka memberikan cara yang sederhana dan nyaman untuk membagi objek data menjadi nilai properti, atau merusaknya.

Misalkan Anda ingin mengambil nilai properti dari objek Recipe dan menetapkan nilai masing-masing properti ke variabel terpisah. Alih-alih kode

 val title = r.title val vegetarian = r.isVegetarian 

dengan pemrosesan berurutan dari setiap properti, Anda dapat menggunakan kode berikut:

 val (title, vegetarian) = r 

Tetapkan hak milik untuk properti pertama dan vegetarian untuk properti kedua.

Kode ini berarti "buat dua variabel, judul dan vegetarian, dan tetapkan nilai salah satu properti r dari setiap variabel." Ia melakukan hal yang sama dengan fragmen berikutnya

 val title = r.component1() val vegetarian = r.component2() 

tapi ternyata lebih kompak.

Operator === selalu memeriksa apakah dua variabel merujuk ke objek yang sama.

Jika Anda ingin memeriksa apakah dua variabel merujuk ke objek yang sama terlepas dari jenisnya, gunakan operator === daripada ==. Operator === memberikan hasil yang benar jika (dan hanya jika) ketika dua variabel berisi referensi ke satu objek aktual. Jika Anda memiliki dua variabel, x dan y, dan ekspresi berikut:

 x === y 

memberikan hasilnya benar, maka Anda tahu bahwa variabel x dan y harus merujuk ke objek yang sama.

Berbeda dengan operator ==, perilaku operator === tidak tergantung pada fungsi equals. Operator === selalu berperilaku sama terlepas dari jenis kelasnya.

Sekarang Anda telah belajar cara membuat dan menggunakan kelas data, buat proyek untuk kode Resep.

Membuat Proyek Resep


Buat proyek Kotlin baru untuk JVM dan beri nama "Resep". Lalu buat yang baru
File Kotlin bernama Recipes.kt: pilih folder src, buka menu File dan pilih perintah
Baru → File / Kelas Kotlin. Masukkan nama file "Resep" dan pilih opsi File di grup Kind.

Kami menambahkan kelas data baru ke proyek yang disebut Resep dan membuat objek data Resep. Di bawah ini adalah kode. Perbarui versi Recipes.kt Anda dan selaraskan dengan versi kami:

 data class Recipe(val title: String, val isVegetarian: Boolean) (  {} ,        .) fun main(args: Array<String>) { val r1 = Recipe("Thai Curry", false) val r2 = Recipe("Thai Curry", false) val r3 = r1.copy(title = "Chicken Bhuna") (  r1    title) println("r1 hash code: ${r1.hashCode()}") println("r2 hash code: ${r2.hashCode()}") println("r3 hash code: ${r3.hashCode()}") println("r1 toString: ${r1.toString()}") println("r1 == r2? ${r1 == r2}") println("r1 === r2? ${r1 === r2}") println("r1 == r3? ${r1 == r3}") val (title, vegetarian) = r1 ( r1) println("title is $title and vegetarian is $vegetarian") } 

Ketika Anda menjalankan kode Anda, teks berikut akan muncul di jendela output IDE:

 r1 hash code: -135497891 r2 hash code: -135497891 r3 hash code: 241131113 r1 toString: Recipe(title=Thai Curry, isVegetarian=false) r1 == r2? true r1 === r2? false r1 == r3? false title is Thai Curry and vegetarian is false 


»Informasi lebih lanjut tentang buku ini dapat ditemukan di situs web penerbit
» Isi
» Kutipan

Diskon 25% untuk kupon untuk Khabrozhitel - Kotlin

Setelah pembayaran versi kertas buku, sebuah buku elektronik dikirim melalui email.

Source: https://habr.com/ru/post/id473614/


All Articles