kotlin数据类
数据类
数据类有点类似java中的实体类,kotlin中可以关键字data class
来声明数据类,完成类似java中lombok的功能。
data class User(val name: String, val age: Int)
对于数据类,kotlin会为primary constructor
的参数(也是属性)自动生成下面的方法:
equals()
/hashCode()
toString()
componentN()
copy()
下面反编译上面定义的User类,看看kotlin编译后的数据类长啥样:javap com.morris.kotlin.dataclass.User
Compiled from “DataClass1.kt”
public final class com.morris.kotlin.dataclass.User {
public final java.lang.String getName();
public final int getAge();
public com.morris.kotlin.dataclass.User(java.lang.String, int);
public final java.lang.String component1();
public final int component2();
public final com.morris.kotlin.dataclass.User copy(java.lang.String, int);
public static com.morris.kotlin.dataclass.User copy$default(com.morris.kotlin.dataclass.User, java.lang.String, int, int, java.lang.Object);
public java.lang.String toString();
public int hashCode();
public boolean equals(java.lang.Object);
}
数据类声明的要点:
primary constructor
至少有一个参数- 所有
primary constructor
都需要声明为val
orvar
,使其成为属性 - 数据类不能是abstract, open, sealed or inner
数据类继承的要点:
- 如果数据类中显示的定义了
equals()
,hashCode()
ortoString()
,或者在数据类的父类将这些方法声明为final,那么这些方法就不会再生成,转而使用已有的。 - 如果父类拥有
componentN()
方法并且是open的以及兼容的返回类型,那么编译器就会生成对应的componentN()
方法并重写父类的方法,如果父类中的方法是不兼容的返回类型或者是final,那么编译器就会报错。 - 在数据类中显示的提供
componentN()
andcopy()
是不被允许的。
当数据类中的属性都有默认值时,kotlin会为数据类提供无参的构造方法:
data class User2(val name: String = "", val age: Int = 0)
生成的数据类反编译后的内容如下:
> javap com.morris.kotlin.dataclass.User2
Compiled from "DataClass1.kt"
public final class com.morris.kotlin.dataclass.User2 {
public final java.lang.String getName();
public final int getAge();
public com.morris.kotlin.dataclass.User2(java.lang.String, int);
public com.morris.kotlin.dataclass.User2(java.lang.String, int, int, kotlin.jvm.internal.DefaultConstructorMarker);
public com.morris.kotlin.dataclass.User2();
public final java.lang.String component1();
public final int component2();
public final com.morris.kotlin.dataclass.User2 copy(java.lang.String, int);
public static com.morris.kotlin.dataclass.User2 copy$default(com.morris.kotlin.dataclass.User2, java.lang.String, int, int, java.lang.Object);
public java.lang.String toString();
public int hashCode();
public boolean equals(java.lang.Object);
}
声明在类中的属性
只有声明在构造方法中的属性才会在toString()
, equals()
, hashCode()
, and copy()
方法有所体现,而直接声明在类中的属性不会。
data class Person(val name: String) {
var age: Int = 0
}
生成的数据类反编译后的内容如下:
> javap com.morris.kotlin.dataclass.Person
Compiled from "DataClass1.kt"
public final class com.morris.kotlin.dataclass.Person {
public final int getAge();
public final void setAge(int);
public final java.lang.String getName();
public com.morris.kotlin.dataclass.Person(java.lang.String);
public final java.lang.String component1();
public final com.morris.kotlin.dataclass.Person copy(java.lang.String);
public static com.morris.kotlin.dataclass.Person copy$default(com.morris.kotlin.dataclass.Person, java.lang.String, int, java.lang.Object);
public java.lang.String toString();
public int hashCode();
public boolean equals(java.lang.Object);
}
也就意味着下面代码中的两个对象是相等的:
fun main() {
val person1 = Person("John")
val person2 = Person("John")
person1.age = 10
person2.age = 20
assert(person1 == person2) // true
}
拷贝
数据类生成的copy()
方法用来拷贝对象的属性,是一个浅拷贝。
User
类的copy()
方法声明如下:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
copy()
方法的使用:
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
println(olderJack) // User(name=Jack, age=2)
注意:copy()
方法是一个浅拷贝,下面的例子证明了这一点:
data class User3(var name : String)
data class Address(var user: User3, var city: String)
fun main() {
var userJack = User3(name="Jack")
var address = Address(user = userJack, city = "London")
var addressCopy = address.copy()
addressCopy.city = "New York"
addressCopy.user.name = "John" // Propagates to `address.user` because they both point to userJack.
println("address.city is ${ address.city}") // Prints "London"
println("address.user.name is ${ address.user.name}") // Prints "John"
}
解构声明
在主构造方法中有多少个参数,就会有多少个componentN()
方法,这些方法的返回值就是对应的属性,是用来实现解构声明的。
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // prints "Jane, 35 years of age"
还没有评论,来说两句吧...