Tìm hiểu về data class trong Kotlin

I, Data class

  • Chúng ta thường xuyên tạo các class với mục đích chính là xử lý data.
  • Ở những class như vậy, chúng ta cần thiết phải implement 1 số phương thức liên quan tới data.
  • Ví dụ 1:Java, việc này hoàn toàn làm bằng tay và khá dài dòng
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class User {

private String name;
private int age;

public Data(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

User user = (User) o;

if (age != user.age) return false;
return name != null ? user.equals(user.name) : user.name == null;

}

@Override
public int hashCode() {
int result = name != null ? user.hashCode() : 0;
result = 31 * result + age;
return result;
}

@Override
public String toString() {
return "Data{" + "name=" + name + ", age=" + age + '}';
}

}
  • Kotlin cung cấp cho chúng ta data class để những class được tạo có mục đích chính là nắm giữ data.
  • Bạn chỉ cần thêm data keyword vào trước class trong khai báo 1 class.
  • Ví dụ 2: data class sẽ implement đầy đủ các phương thức hơn so với ví dụ 1
1
data class User(val name: String, val age: Int)
  • Compiler sẽ tự động compile để implement các function dựa trên các property được khai báo ở primary constructor:
    • 1, equals(), hashCode().
    • 2, toString() với định dạng "User(name=John, age=42)".
    • 3, ComponentN() để get các property dựa trên thứ tự sắp xếp của chúng như val name: String = person.component1(), val age: Int = person.component2().
    • 4, copy() (mình sẽ nói rõ hơn ở III).
  • Data class cũng cần phải tuân thủ các quy định sau:
    • 1, Primary constructor cần ít nhất 1 parameter.
    • 2, Tất cả parameter của primary constructor phải được sử dụng với val hoặc var.
    • 3, Data class không thể là abstract, open, sealed hoặc inner class (static nested class vãn được nhé).

II, Property ở body class

  • Ở trên mình nói nhiều đến parameter ở trong primary constructor, nhưng nếu bạn khai báo property trong body class thì sao ?
  • Chỉ có các paramter ở trong primary constructor được sử dụng cho equals(), hashCode(), toString(), copy()componentN().
  • Ví dụ 3: chỉ có name parameter được sử dụng và chỉ có 1 method component1() được sinh ra.
1
2
3
4
5
6
7
8
9
10
11
12
13
data class Person(val name: String) {
var age: Int = 0
}

fun main() {
val person1 = Person("John")
val person2 = Person("John")
person1.age = 10
person2.age = 20
println("person1 == person2: ${person1 == person2}") // return true
println("person1 with age ${person1.age}: ${person1}") // person1 with age 10: Person(name=John)
println("person2 with age ${person2.age}: ${person2}") // person2 with age 20: Person(name=John)
}
  • Do age không được sử dụng, do đó nếu 2 variable Personage khác nhau nhưng name bằng nhau thì 2 variable Person vẫn bằng nhau.

III, Copy()

  • Phương thức copy() được sử dụng nếu bạn muốn tạo ra 1 Object mới:
    • 1, có cùng type.
    • 2, Object mới copy 1 vài parameter(các paramter không đổi) hoặc copy tất cả.
  • Ví dụ 4: class Person ở ví dụ 2 implement copy() như sau:
1
2
3
4
5
6
7
data class User(val name: String, val age: Int){ 

fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
}

val itLife = User(name = "IT life", age = 20)
val copyIt = itLife.copy(age = 20)

IV, Standard data class

  • Standard library cung cấp 2 data class là PairTriple.
  • Ví dụ 5: xem source code của PairTriple trong Tuples.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// `Pair` data class
public data class Pair<out A, out B>(
public val first: A ,
public val second: B
) : Serializable {

public override fun toString(): String = "($first, $second)"
}

// `Triple` data class
public data class Triple<out A, out B, out C>(
public val first: A,
public val second: B,
public val third: C
) : Serializable {

public override fun toString(): String = "($first, $second, $third)"
}