我正在参加「启航方案」

Kotlin是由JetBrains开发的针对JVM、Android浏览器的静态编程言语,是Android的官方言语。Kotlin拥有较多高档而又简练的语法特性,提升了咱们的开发效率,减少了代码量。

在运用 java 的时分,咱们在用class界说一个entity时除了写get、set办法(运用Kotlin后省了这部分工作),经常还会重写类的 equalshashCodetoString办法,这些办法往往都是模板化的。在 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)
    

重写hashCodeequals办法

  • 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类编译后的代码多了部分办法,新增了componentscopy办法,重写了equalshashCodetoString办法。

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有必要运用 Kotlindata class,copy办法的应用自然少不了。
  • 重写equalshasCode办法,equals()办法不再单一比较目标引用,而是先判断两个是否是同一个目标,假如不是则进行类型判断,是相同类型则逐一比较特点的值。

运用data class需求留意啥

  • 主结构函数有必要要至少有一个参数。
  • 主结构函数中的所有参数有必要被标记为val或者var。
  • 数据类不能有以下修饰符:abstract、inner、open、sealed。