12-bo‘lim

data class, object va enum

data class bir qatorda nimalarni beradi, copy va yoyish, object bilan yakka nusxa, companion object va enum sinflari.

🕑 13 daqiqa o‘qish 📄 718 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. data class
  2. copy
  3. Yoyish
  4. data class cheklovlari
  5. object - yakka nusxa
  6. companion object
  7. enum class
  8. enum - xossalar bilan
  9. when va enum
  10. Xulosa

Kotlin da uch xil maxsus sinf bor. Har biri ma'lum bir vazifani juda qisqa hal qiladi.

data class #

KOTLIN
data class Talaba(val ism: String, val ball: Int)

fun main() {
    val a = Talaba("Malika", 88)
    val b = Talaba("Malika", 88)

    println(a)
    println(a == b)
    println(a.hashCode() == b.hashCode())
    println(a.ism)
}
Natija
Talaba(ism=Malika, ball=88)
true
true
Malika

Bitta so'z - data - qo'shildi va kompilyator to'rtta narsani yozib berdi:

NimaVazifasi
toString()O'qishga qulay ko'rinish
equals()Mazmun bo'yicha solishtirish
hashCode()Set va Map da to'g'ri ishlash
copy()Nusxa olish
componentN()Yoyish uchun

Oldingi bo'limda buni qo'lda yozgandik - yigirmaga yaqin qator edi.

copy #

KOTLIN
data class Talaba(val ism: String, val ball: Int, val guruh: String)

fun main() {
    val asl = Talaba("Malika", 88, "A")

    val yangiBall = asl.copy(ball = 95)
    val boshqaGuruh = asl.copy(guruh = "B")
    val toliqNusxa = asl.copy()

    println(asl)
    println(yangiBall)
    println(boshqaGuruh)
    println(asl == toliqNusxa)
    println(asl === toliqNusxa)
}
Natija
Talaba(ism=Malika, ball=88, guruh=A)
Talaba(ism=Malika, ball=95, guruh=A)
Talaba(ism=Malika, ball=88, guruh=B)
true
false

copy - "shu obyektning nusxasini ol, faqat bu maydonni o'zgartir". val xossalar o'zgarmasligi uchun bu asosiy o'zgartirish usuli.

O'zgarmas obyektlar - Kotlin uslubi

data class ni odatda faqat val bilan yozadilar.

Obyektni o'zgartirish o'rniga - yangi nusxa yaratiladi. Bu dastlab g'alati tuyuladi, lekin katta foyda beradi: obyektni funksiyaga uzatganingizda, u sizning nusxangizni o'zgartirib qo'ymasligiga ishonch hosil qilasiz.

Ayniqsa ko'p oqimli dasturda bu muhim - o'zgarmas obyekt hech qachon "yarim o'zgargan" holatda ko'rinmaydi.

Yoyish #

KOTLIN
data class Nuqta(val x: Int, val y: Int)

fun main() {
    val n = Nuqta(3, 7)

    val (x, y) = n
    println("x=$x, y=$y")

    val nuqtalar = listOf(Nuqta(1, 2), Nuqta(3, 4))
    for ((a, b) in nuqtalar) {
        println("$a-$b")
    }

    val (ism, ball) = Pair("Aziza", 95)
    println("$ism: $ball")
}
Natija
x=3, y=7
1-2
3-4
Aziza: 95

val (x, y) = n - yoyish (destructuring). U componentN() funksiyalariga tayanadi va ularni data class avtomatik yozadi.

Yoyish tartibga bog'liq, nomga emas

val (x, y) = nuqta da x birinchi maydonni, y ikkinchisini oladi - nomlari qanday bo'lishidan qat'i nazar.

Ya'ni val (y, x) = nuqta deb yozsangiz, qiymatlar almashib ketadi va kompilyator hech narsa demaydi.

Shuning uchun uch-to'rtta maydondan ko'p bo'lsa, yoyish o'rniga nuqta.x deb yozgan xavfsizroq.

data class cheklovlari #

Nimalar hisobga olinmaydi

equals, hashCode, toString va copy faqat asosiy konstruktordagi xossalarni ko'radi.

KOTLIN
data class Talaba(val ism: String) {
    var ball: Int = 0
}

Bu yerda ball - tanadagi xossa, shuning uchun ikki obyekt turli ballar bilan ham teng hisoblanadi. Bu ko'pincha kutilmagan natija beradi.

Qoida: taqqoslashga kirishi kerak bo'lgan hamma narsani asosiy konstruktorga qo'ying.

KOTLIN
data class Talaba(val ism: String) {
    var ball: Int = 0
}

fun main() {
    val a = Talaba("Malika")
    val b = Talaba("Malika")
    a.ball = 88
    b.ball = 50

    println(a == b)
    println(a)
}
Natija
true
Talaba(ism=Malika)

Ko'rib turganingizdek, ball na taqqoslashda, na toString da qatnashdi.

object - yakka nusxa #

KOTLIN
object Sozlama {
    var til = "uz"
    val versiya = "1.0"

    fun korsat() = "Til: $til, versiya: $versiya"
}

fun main() {
    println(Sozlama.korsat())

    Sozlama.til = "en"
    println(Sozlama.til)

    val a = Sozlama
    val b = Sozlama
    println(a === b)
}
Natija
Til: uz, versiya: 1.0
en
true

object - sinf va uning yagona nusxasi bir vaqtda. Uni new qilish kerak emas va ikkinchi nusxa hech qachon yaratilmaydi.

Bu singleton namunasi bo'lib, boshqa tillarda uni qo'lda yozish kerak bo'ladi.

companion object #

KOTLIN
class Talaba private constructor(val ism: String, val ball: Int) {

    companion object {
        const val ENG_YUQORI = 100

        fun yarat(ism: String, ball: Int): Talaba? {
            if (ball !in 0..ENG_YUQORI) return null
            return Talaba(ism, ball)
        }

        fun bosh() = Talaba("noma'lum", 0)
    }

    override fun toString() = "$ism ($ball)"
}

fun main() {
    println(Talaba.ENG_YUQORI)
    println(Talaba.yarat("Malika", 88))
    println(Talaba.yarat("Xato", 150))
    println(Talaba.bosh())
}
Natija
100
Malika (88)
null
noma'lum (0)

companion object - sinfga tegishli (obyektga emas) a'zolar uchun. Boshqa tillardagi static ning o'rnini bosadi.

Bu yerda konstruktor private qilingan va obyekt faqat yarat orqali yaratiladi - u qiymatni tekshiradi va noto'g'ri bo'lsa null qaytaradi.

Kotlin da static yo'q

Kotlin da static kalit so'zi umuman yo'q.

Uning o'rnida uch vosita bor:

  1. Yuqori darajadagi funksiya va o'zgaruvchi - fayl ichida, sinfdan tashqarida. Ko'p hollarda eng to'g'ri tanlov.
  2. object - holatga ega yakka nusxa kerak bo'lsa.
  3. companion object - a'zo aynan shu sinfga bog'liq bo'lsa.

Yordamchi funksiya yozayotgan bo'lsangiz, uni sinfga tiqishdan oldin o'ylab ko'ring: balki oddiy yuqori darajadagi funksiya yetarlidir.

enum class #

KOTLIN
enum class Holat {
    YANGI, KORILMOQDA, BAJARILDI
}

fun main() {
    val h = Holat.KORILMOQDA

    println(h)
    println(h.name)
    println(h.ordinal)
    println(Holat.valueOf("YANGI"))
    println(Holat.entries)

    println(Holat.entries.joinToString(" ") { "${it.ordinal}:${it.name}" })
}
Natija
KORILMOQDA
KORILMOQDA
1
YANGI
[YANGI, KORILMOQDA, BAJARILDI]
0:YANGI 1:KORILMOQDA 2:BAJARILDI

Diqqat: println(h) nomni chiqardi. Ba'zi tillarda bu yerda raqam chiqadi - Kotlin da esa yo'q.

enum - xossalar bilan #

KOTLIN
enum class Daraja(val chegara: Int, val belgi: String) {
    PAST(0, "-"),
    ORTA(60, "+"),
    YUQORI(85, "*");

    fun tavsif() = "$name (${chegara}dan yuqori) $belgi"
}

fun baho(ball: Int): Daraja = when {
    ball >= Daraja.YUQORI.chegara -> Daraja.YUQORI
    ball >= Daraja.ORTA.chegara -> Daraja.ORTA
    else -> Daraja.PAST
}

fun main() {
    for (d in Daraja.entries) {
        println(d.tavsif())
    }

    println(baho(92))
    println(baho(70))
    println(baho(30))
}
Natija
PAST (0dan yuqori) -
ORTA (60dan yuqori) +
YUQORI (85dan yuqori) *
YUQORI
ORTA
PAST

enum da konstruktor, xossa va metod bo'lishi mumkin. Qiymatlar ro'yxatidan keyin nuqtali vergul qo'yiladi - bu Kotlin da nuqtali vergul haqiqatan kerak bo'ladigan kam joylardan biri.

when va enum #

KOTLIN
enum class Yonalish { SHIMOL, JANUB, SHARQ, GARB }

fun teskari(y: Yonalish): Yonalish = when (y) {
    Yonalish.SHIMOL -> Yonalish.JANUB
    Yonalish.JANUB -> Yonalish.SHIMOL
    Yonalish.SHARQ -> Yonalish.GARB
    Yonalish.GARB -> Yonalish.SHARQ
}

fun main() {
    for (y in Yonalish.entries) {
        println("$y -> ${teskari(y)}")
    }
}
Natija
SHIMOL -> JANUB
JANUB -> SHIMOL
SHARQ -> GARB
GARB -> SHARQ
enum bilan when da else kerak emas

Yuqoridagi when da else tarmog'i yo'q - va kompilyator shikoyat qilmadi.

Sababi: u Yonalish ning hamma qiymati qamrab olinganini ko'rdi.

Bu katta afzallik: enum ga yangi qiymat qo'shsangiz, kompilyator shu when ni ko'rsatib, "bu holat qamrab olinmagan" deydi. else yozgan bo'lsangiz, xato jimgina o'tib ketardi.

Amaliy topshiriq
  1. Kitob ni data class qilib yozing va println bilan chiqaring.
  2. Ikkita bir xil obyektni == bilan solishtiring.
  3. copy bilan faqat narxni o'zgartirgan nusxa oling.
  4. val (a, b) = obyekt bilan yoying.
  5. Tanadagi xossa equals ga kirmasligini isbotlang.
  6. object bilan sozlamalar saqlovchi yakka nusxa yarating.
  7. companion object da yaratuvchi funksiya yozing.
  8. Konstruktorni private qilib, faqat shu funksiya orqali yarating.
  9. Hafta kunlari uchun enum yozing.
  10. enum ga xossa qo'shing va when da else siz ishlating.

Xulosa #

  • data class bir so'z bilan toString, equals, hashCode, copy va yoyishni beradi.
  • copy(maydon = yangi) - o'zgarmas obyektni "o'zgartirish" usuli.
  • Yoyish tartibga bog'liq, nomga emas.
  • equals va toString faqat asosiy konstruktordagi xossalarni ko'radi.
  • object - singleton; companion object - sinfga tegishli a'zolar.
  • Kotlin da static yo'q; ko'pincha yuqori darajadagi funksiya yetarli.
  • enum da println nomni chiqaradi; entries hamma qiymatni beradi.
  • enum bilan when da else kerak emas - bu kelajakdagi xatolardan saqlaydi.

Keyingi bo'limda vorislik, interfeys va sealed sinflarni ko'ramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.