Menu
CoddyTech

Lớp dữ liệu

Thuộc phần Lập trình hướng đối tượng trong hành trình Kotlin của Coddy. Bài học 32 trên 57.

lớp dữ liệu là lớp có nhiệm vụ chính là lưu trữ dữ liệu. Từ bổ nghĩa data giúp trình biên dịch tạo toString(), equals(), hashCode(), copy() và componentN() từ các thuộc tính của hàm khởi tạo chính:

data class Point(val x: Int, val y: Int)

Bên trong main:

val a = Point(1, 2)
val b = Point(1, 2)
println(a)
println(a == b)
println(setOf(a, b).size)

Đầu ra:

Point(x=1, y=2)
true
1

Khi không có data, println hiển thị tên lớp và một mã băm như Point@1b6d3586, còn hai đối tượng có cùng giá trị thì không bằng nhau. copy() tạo một đối tượng mới với một số thuộc tính đã thay đổi và giữ nguyên đối tượng ban đầu, vì vậy lớp dữ liệu có các thuộc tính val hoạt động như một giá trị bất biến:

data class User(val name: String, val email: String, val admin: Boolean = false)

Bên trong main:

val ada = User("Ada", "ada@example.com")
val boss = ada.copy(admin = true)
println(ada)
println(boss)
println(ada == boss)

Đầu ra:

User(name=Ada, email=ada@example.com, admin=false)
User(name=Ada, email=ada@example.com, admin=true)
false

Khai báo phân rã tách một đối tượng thành các biến: val (x, y) = point gọi component1() và component2() được tạo tự động theo thứ tự của hàm khởi tạo. Cách này cũng dùng được trong vòng lặp for và tham số lambda. _ bỏ qua một thuộc tính:

data class Score(val player: String, val points: Int, val level: Int)

Bên trong main:

val scores = listOf(Score("ada", 120, 3), Score("bo", 95, 2))
for ((player, points) in scores) println("$player: $points")
val (_, bestPoints, bestLevel) = scores.maxBy { it.points }
println("best: $bestPoints at level $bestLevel")

Đầu ra:

ada: 120
bo: 95
best: 120 at level 3

Chỉ các thuộc tính trong hàm khởi tạo chính mới được tính: thuộc tính khai báo trong thân lớp sẽ không được đưa vào toString, equals, hashCode và copy. Lớp dữ liệu cần ít nhất một tham số hàm khởi tạo, và mọi tham số phải là val hoặc var:

data class Reading(val sensor: String, val value: Int) {
    var note = ""
}

Bên trong main:

val r1 = Reading("t1", 20)
val r2 = Reading("t1", 20)
r1.note = "checked"
println(r1)
println(r1 == r2)

Đầu ra:

Reading(sensor=t1, value=20)
true
challenge icon

Thử thách

Dễ

Biến Book thành lớp dữ liệu để khi in ra, lớp hiển thị giá trị và so sánh theo giá trị. Sau đó hoàn thành ba hàm: parse(line) chuyển Dune;Herbert;1965 thành một Book, newEdition(book, year) trả về một bản sao có năm mới và thêm (new edition) vào tiêu đề, còn describe(book) trả về Dune by Herbert, 1965 bằng cách dùng khai báo phân rã.

Code được cung cấp phân tích từng dòng đầu vào, in ra từng cuốn sách, số lượng bản trùng lặp, ấn bản mới của cuốn sách đầu tiên (năm 2024) và phần mô tả của từng cuốn sách riêng biệt.

Đặt code của bạn trong Book.kt và BookTools.kt. Main.kt chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.

Tự làm thử

fun main() {
    // Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
    val input = generateSequence(::readLine).toList()
    val books = input.map { parse(it) }
    for (b in books) println(b)
    println("duplicates: ${books.size - books.distinct().size}")
    println(newEdition(books[0], 2024))
    for (b in books.distinct()) println(describe(b))
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Playground Kotlin