聊一聊Kotlin之data class
Kotlin是由JetBrains开发的针对JVM、Android和浏览器的静态编程语言,是Android的官方语言。Kotlin拥有较多高级而又简洁的语法特性,提升了我们的开发效率,减少了代码量。
在使用 java 的时候,我们在用class定义一个entity时除了写get、set方法(使用Kotlin后省了这部分工作),经常还会重写类的 equals
、hashCode
和toString
方法,这些方法往往都是模板化的。在 kotlin 中提供了data class
搞定这些模版化代码。
data class与class的区别:
实现方式
- class类
class ClassUser(val name: String, var age: Int)
- data class类
data class DataClassUser(val name: String, var age: Int)
自动重写toString
方法
- data类的
toString
方法会打印出属性的值 - 非data类的
toString
方法则打印出内存地址val classUser = ClassUser("classuser", 18)
val dataClassUser = DataClassUser("dataclassuser", 20)
println("ClassUser -> ${classUser.toString()}")
// ClassUser -> com.imock.vicjava.keyuse.ClassUser@11026067
println("DataClassUser -> ${dataClassUser.toString()}")
// DataClassUser -> DataClassUser(name=dataclassuser, age=20)
新增componentN
方法
- data类新增属性的
componentN
方法,component1
代表第一个属性,component2
代表第二个属性。(常用于解构声明)val dataClassUser = DataClassUser("dataclassuser", 20)
println("DataClassUser component1() -> ${dataClassUser.component1()}")
// DataClassUser component1() -> dataclassuser
println("DataClassUser component2() -> ${dataClassUser.component2()}")
// DataClassUser component2() -> 20
新增copy
方法
- data类新增
copy
方法,可以用来修改部分属性,但是保持其他不变。val dataClassUser = DataClassUser("dataclassuser", 20)
println("ClassUser toString() -> ${classUser.toString()}")
// DataClassUser -> DataClassUser(name=dataclassuser, age=20)
val newDataClassUser = dataClassUser.copy(age = 22)
println("DataClassUser copy -> ${newDataClassUser.toString()}")
// DataClassUser copy -> DataClassUser(name=dataclassuser, age=22)
重写hashCode
和 equals
方法
- data类重写
hashCode
方法,equals
方法可以稍后看下源码,先判断两个是否是同一个对象,如果不是则进行类型判断,是相同类型则逐个比较属性的值。val classUserLisa1 = ClassUser("lisa", 20)
val classUserLisa2 = ClassUser("lisa", 20)
println("ClassUser equals -> ${classUserLisa1.equals(classUserLisa2)}")
// ClassUser equals -> false
println("classUserLisa1 hashCode -> ${classUserLisa1.hashCode()}")
// classUserLisa1 hashCode -> 2081652693
println("classUserLisa2 hashCode -> ${classUserLisa2.hashCode()}")
// classUserLisa2 hashCode -> 406765571
val dataClassUserLisa1 = DataClassUser("lisa", 20)
val dataClassUserLisa2 = DataClassUser("lisa", 20)
println("DataClassUser equals -> ${dataClassUserLisa1.equals(dataClassUserLisa2)}")
// DataClassUser equals -> true
println("dataClassUserLisa1 hashCode -> ${dataClassUserLisa1.hashCode()}")
// dataClassUserLisa1 hashCode -> 102981865
println("dataClassUserLisa2 hashCode -> ${dataClassUserLisa2.hashCode()}")
// dataClassUserLisa2 hashCode -> 102981865
data class为何如此神奇
data class DataClassUser(val name: String, var age: Int)
class ClassUser(var name: String, var age: Int)
单独看实现上两者没有太大的区别,一个使用data class,一个使用class,为何data class却多出那么多能力?得益于Kotlin高级的语法特性。我们都知道kotlin最终还是要编译成 java class 在 JVM 上运行的,为了更好的理解Kotlin高级而又简洁的语法特性,有时我们需要看看用kotlin写完的代码编译后是什么样子。Talk is cheap, show me the code.
class类编译后的java代码
Kotlin写法如下:
class ClassUser(var name: String, var age: Int)
查看编译后的java代码如下,可以看到帮我们自动生成了get、set和构造方法:
public final class ClassUser {
@NotNull
private final String name;
private int age;
@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 ClassUser(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = age;
}
}
data class类编译后的java代码
Kotlin写法如下:
data class DataClassUser(val name: String, var age: Int)
查看其编译后的java代码如下,会发现比class类编译后的代码多了部分方法,新增了components
和copy
方法,重写了equals
、hashCode
和toString
方法。
public final class DataClassUser {
@NotNull
private final String name;
private int age;
@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 DataClassUser(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = age;
}
// 新增方法
@NotNull
public final String component1() {
return this.name;
}
// 新增方法
public final int component2() {
return this.age;
}
// 新增方法
@NotNull
public final DataClassUser copy(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
return new DataClassUser(name, age);
}
// 新增方法
// $FF: synthetic method
public static DataClassUser copy$default(DataClassUser var0, String var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.name;
}
if ((var3 & 2) != 0) {
var2 = var0.age;
}
return var0.copy(var1, var2);
}
// 重写该方法
@NotNull
public String toString() {
return "DataClassUser(name=" + this.name + ", age=" + this.age + ")";
}
// 重写该方法
public int hashCode() {
String var10000 = this.name;
return (var10000 != null ? var10000.hashCode() : 0) * 31 + Integer.hashCode(this.age);
}
// 重写该方法
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof DataClassUser) {
DataClassUser var2 = (DataClassUser)var1;
if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {
return true;
}
}
return false;
} else {
return true;
}
}
}
总结
知道data class
干了啥
- 重写
toString
方法。 - 新增
componentN
方法(component1()、component2()、...、componentN()
),其对应属性的声明顺序(常用于解构声明)。 - 新增
copy
方法,可以用来修改部分属性,但是保持其他不变。
特别提下copy方法,可能有些同学疑问很少见到这个方法使用场景,慢慢地等你用上了MVI框架就知道State必须使用 Kotlin data class,copy方法的应用自然少不了。 - 重写
equals
和hasCode
方法,equals()
方法不再单一比较对象引用,而是先判断两个是否是同一个对象,如果不是则进行类型判断,是相同类型则逐个比较属性的值。
使用data class
需要注意啥
- 主构造函数必须要至少有一个参数。
- 主构造函数中的所有参数必须被标记为val或者var。
- 数据类不能有以下修饰符:abstract、inner、open、sealed。
作者:聆听Tech
链接:https://juejin.cn/post/7156233100199100447
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://juejin.cn/post/7156233100199100447
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。