本節(jié)介紹kotlin的data class(數(shù)據(jù)類)
1赌渣、數(shù)據(jù)類的定義和反編譯分析
在Java中數(shù)據(jù)類中具有的 getter,setter方法韭山,可以通過(guò) IDEA或者eclipse來(lái)生成代碼障陶,但是有很多的冗余
當(dāng)然我們也可以使用Java的插件,lombok券勺,僅用幾個(gè)注釋就能解決蚕苇。
1.1、數(shù)據(jù)類的定義
但是在kotlin中检眯,我們可以直接使用 data 關(guān)鍵字來(lái)定義數(shù)據(jù)類
注意數(shù)據(jù)類的前提條件:
- 1厘擂、主構(gòu)造方法至少要有一個(gè)參數(shù)
- 2、所有的主構(gòu)造方法參數(shù)都需要被標(biāo)記為 var 或者 val
- 3锰瘸、數(shù)據(jù)類不能是抽象刽严、open的、sealed(密封類)避凝、inner的類
數(shù)據(jù)類的定義示例:
data class Person(val name: String, var age: Int, var address: String)
數(shù)據(jù)類的使用:
fun main() {
val person = Person("zhangsan", 20, "beijing")
println(person)
}
1.2舞萄、數(shù)據(jù)類的反編譯分析
接下來(lái)眨补,我們可以使用反編譯,對(duì)上面生成的數(shù)據(jù)類進(jìn)行深度的分析倒脓。(關(guān)于反編譯知識(shí)撑螺,看一看我之前的博客,點(diǎn)這里 ) 崎弃,以下是反編譯結(jié)果:
Compiled from "DataClass.kt"
public final class com.liang.kotlin.basic.data_class.Person {
public final java.lang.String getName();
Code:
0: aload_0
1: getfield #11 // Field name:Ljava/lang/String;
4: areturn
public final int getAge();
Code:
0: aload_0
1: getfield #19 // Field age:I
4: ireturn
public final void setAge(int);
Code:
0: aload_0
1: iload_1
2: putfield #19 // Field age:I
5: return
public final java.lang.String getAddress();
Code:
0: aload_0
1: getfield #26 // Field address:Ljava/lang/String;
4: areturn
public final void setAddress(java.lang.String);
Code:
0: aload_1
1: ldc #29 // String <set-?>
3: invokestatic #35 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
6: aload_0
7: aload_1
8: putfield #26 // Field address:Ljava/lang/String;
11: return
public com.liang.kotlin.basic.data_class.Person(java.lang.String, int, java.lang.String);
Code:
0: aload_1
1: ldc #38 // String name
3: invokestatic #35 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
6: aload_3
7: ldc #39 // String address
9: invokestatic #35 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
12: aload_0
13: invokespecial #42 // Method java/lang/Object."<init>":()V
16: aload_0
17: aload_1
18: putfield #11 // Field name:Ljava/lang/String;
21: aload_0
22: iload_2
23: putfield #19 // Field age:I
26: aload_0
27: aload_3
28: putfield #26 // Field address:Ljava/lang/String;
31: return
public final java.lang.String component1();
Code:
0: aload_0
1: getfield #11 // Field name:Ljava/lang/String;
4: areturn
public final int component2();
Code:
0: aload_0
1: getfield #19 // Field age:I
4: ireturn
public final java.lang.String component3();
Code:
0: aload_0
1: getfield #26 // Field address:Ljava/lang/String;
4: areturn
public final com.liang.kotlin.basic.data_class.Person copy(java.lang.String, int, java.lang.String);
Code:
0: aload_1
1: ldc #38 // String name
3: invokestatic #35 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
6: aload_3
7: ldc #39 // String address
9: invokestatic #35 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
12: new #2 // class com/liang/kotlin/basic/data_class/Person
15: dup
16: aload_1
17: iload_2
18: aload_3
19: invokespecial #49 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
22: areturn
public static com.liang.kotlin.basic.data_class.Person copy$default(com.liang.kotlin.basic.data_class.Person, java.lang.String, int, java.lang.String, int, java.lang.Object);
Code:
0: iload 4
2: iconst_1
3: iand
4: ifeq 12
7: aload_0
8: getfield #11 // Field name:Ljava/lang/String;
11: astore_1
12: iload 4
14: iconst_2
15: iand
16: ifeq 24
19: aload_0
20: getfield #19 // Field age:I
23: istore_2
24: iload 4
26: iconst_4
27: iand
28: ifeq 36
31: aload_0
32: getfield #26 // Field address:Ljava/lang/String;
35: astore_3
36: aload_0
37: aload_1
38: iload_2
39: aload_3
40: invokevirtual #53 // Method copy:(Ljava/lang/String;ILjava/lang/String;)Lcom/liang/kotlin/basic/data_class/Person;
43: areturn
public java.lang.String toString();
Code:
0: new #56 // class java/lang/StringBuilder
3: dup
4: invokespecial #57 // Method java/lang/StringBuilder."<init>":()V
7: ldc #59 // String Person(name=
9: invokevirtual #63 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
12: aload_0
13: getfield #11 // Field name:Ljava/lang/String;
16: invokevirtual #63 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: ldc #65 // String , age=
21: invokevirtual #63 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: aload_0
25: getfield #19 // Field age:I
28: invokevirtual #68 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
31: ldc #70 // String , address=
33: invokevirtual #63 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: aload_0
37: getfield #26 // Field address:Ljava/lang/String;
40: invokevirtual #63 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: ldc #72 // String )
45: invokevirtual #63 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
48: invokevirtual #74 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
51: areturn
public int hashCode();
Code:
0: aload_0
1: getfield #11 // Field name:Ljava/lang/String;
4: dup
5: ifnull 14
8: invokevirtual #77 // Method java/lang/Object.hashCode:()I
11: goto 16
14: pop
15: iconst_0
16: bipush 31
18: imul
19: aload_0
20: getfield #19 // Field age:I
23: invokestatic #82 // Method java/lang/Integer.hashCode:(I)I
26: iadd
27: bipush 31
29: imul
30: aload_0
31: getfield #26 // Field address:Ljava/lang/String;
34: dup
35: ifnull 44
38: invokevirtual #77 // Method java/lang/Object.hashCode:()I
41: goto 46
44: pop
45: iconst_0
46: iadd
47: ireturn
public boolean equals(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: if_acmpeq 56
5: aload_1
6: instanceof #2 // class com/liang/kotlin/basic/data_class/Person
9: ifeq 58
12: aload_1
13: checkcast #2 // class com/liang/kotlin/basic/data_class/Person
16: astore_2
17: aload_0
18: getfield #11 // Field name:Ljava/lang/String;
21: aload_2
22: getfield #11 // Field name:Ljava/lang/String;
25: invokestatic #91 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
28: ifeq 58
31: aload_0
32: getfield #19 // Field age:I
35: aload_2
36: getfield #19 // Field age:I
39: if_icmpne 58
42: aload_0
43: getfield #26 // Field address:Ljava/lang/String;
46: aload_2
47: getfield #26 // Field address:Ljava/lang/String;
50: invokestatic #91 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
53: ifeq 58
56: iconst_1
57: ireturn
58: iconst_0
59: ireturn
}
通過(guò)上面的反編譯甘晤,我們可以清楚的看到:
編譯器做增加了一下內(nèi)容:
1、equals/hasCode
2饲做、toString(),形式為:Person(name=..., age=..., address=...)
3安皱、針對(duì)屬性的componentN方法,并且是按照屬性的聲明順序來(lái)生成的
4艇炎、copy方法
2酌伊、數(shù)據(jù)類方法說(shuō)明
通過(guò)上面的反編譯class,接下來(lái)對(duì)編譯器生成出來(lái)的函數(shù)進(jìn)行探索缀踪。
2.1居砖、componentN()
componentN的方法主要在于,解構(gòu)聲明:
- 解構(gòu):在主構(gòu)造方法中有多少個(gè)參數(shù)就會(huì)生成多少個(gè) component方法 (component1,component2... )
- 這些方法返回對(duì)應(yīng)字段的值驴娃,component方法是用來(lái)實(shí)現(xiàn) 解構(gòu)聲明的
演示如圖所示:
2.2奏候、copy()
copy() : 作用在賦值的時(shí)候,很方便唇敞,
在Java中蔗草,一個(gè)對(duì)象的類成員如果如果被另一個(gè)對(duì)象復(fù)制,僅僅修改了一個(gè)參數(shù)疆柔,那么需要把這個(gè)對(duì)象的所有值都賦值給另一個(gè)對(duì)象咒精,這樣是非常麻煩的。
在kotlin中旷档,可以通過(guò)copy()方法執(zhí)行修改某一個(gè)參數(shù)
注意: 如果不加參數(shù)名字模叙,那么默認(rèn)是第一個(gè),必須明確參數(shù)名