数据类
数据类(Data Class) 顾名思义,用于存放数据的类,Kotlin 规划者深知开发者需求的数据类应该具有哪些能力,乃至直接为其规划了一个关键字 data,所以通过 data class 界说的数据类从规划层面就支撑自动生成一些例如 equals、hashCode 之类的办法,方便了开发者的同时其中也有一些值得注意的细节,我们把它反编译成 Java 代码便可一目了然
data 关键字带来的改变
如下是两个数据类,仅有差异就是一个有 data 关键字,一个没有
class Person(
val name: String,
var age: String,
val isAdult: Boolean,
)
data class DataPerson(
val name: String,
var age: String,
val isAdult: Boolean,
)
反编译成 Java 代码的差异比照
public final class Person {
private final String name;
private int age;
private final boolean isAdult;
public final String getName()
public final int getAge()
public final void setAge(int age)
public final boolean isAdult()
public Person(@NotNull String name, int age, boolean isAdult) {
this.name = name;
this.age = age;
this.isAdult = isAdult;
}
}
public final class DataPerson {
// ... 省掉相同部分
public final <Type> componentN()
public final DataPerson copy(@NotNull String name, int age, boolean isAdult)
public String toString()
public int hashCode()
public boolean equals(@Nullable Object var1)
}
能够看到添加了 data 关键字之后编译器为我们自动生成了一些有用的办法
- componentN() 用于解构声明
- copy()
- toString()
- hashCode()
- equals()
派生特点
创立数据类时,有些特点能够通过其它特点计算得到,这时候要依据情况挑选是否使用 getter
class Person(
val name: String,
var age: String,
) {
val isAdult = age > 17 // ① ❌
val adult get() = age > 17 // ② ✅
}
代码 ① 特点会被声明为 final 类型并初始化在结构办法中,代码 ② 特点则会直接被编译成 get 办法,如下是对应反编译的 Java 代码
public final class Person {
private final boolean isAdult;
@NotNull
private final String name;
private int age;
public final boolean isAdult() {
return this.isAdult;
}
public final boolean getAdult() {
return this.age > 17;
}
@NotNull
public final String getName() {
return this.name;
}
public final int getAge() {
return this.age;
}
public final void setAge(int var1) {
this.age = var1;
}
public Person(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = age;
this.isAdult = this.age > 17;
}
}
可见 Person 被创立之后,假如 age 被改变,isAdult 的成果不会受到影响,由于它在对象初始化的时候就计算出固定成果了。adult 的成果会对应发生预期的改变
fun main() {
val person = Person(name = "", age = 17)
person.age = 18
println("isAdult ${person.isAdult}") // false
println("adult ${person.adult}") // true
}
所以,关于那些依据可变特点的改变而派生出来的特点,需求自界说 getter 而不是直接赋予表达式。依据不可变特点派生出来的特点则不需求 getter
class Rectangle(val width: Int, val height: Int) {
val area = this.width * this.height // ✅
}