Kotlin - 数据类

433 阅读2分钟

顾名思义,数据类就是只存储数据,不包含操作行为的类。Kotlin 中的数据类可以为我们节省大量的样板代码(Java 中强制我们要去写一堆 getter、setter 代码,而实际上这些方法都是 “不言自明” 的),这样最终的代码更易于理解,便于维护。

创建数据类

使用关键字为 data class 创建一个只包含数据的类:

data class LoginUser(val username: String, val password: String)

选择菜单栏中的 Tools|Kotlin|Show Kotlin Bytecode 命令

image.png

在弹出的对话框中单击 Decompile 按钮

image.png 反编译之后的 Java 代码:

import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class LoginUser {
   @NotNull
   private final String username;
   @NotNull
   private final String password;

   @NotNull
   public final String getUsername() {
      return this.username;
   }

   @NotNull
   public final String getPassword() {
      return this.password;
   }

   // 构造函数
   public LoginUser(@NotNull String username, @NotNull String password) {
      Intrinsics.checkNotNullParameter(username, "username");
      Intrinsics.checkNotNullParameter(password, "password");
      super();
      this.username = username;
      this.password = password;
   }

   @NotNull
   public final String component1() { // component1()函数,返回第 1 个成员值 username
      return this.username;
   }

   @NotNull
   public final String component2() { // component2()函数,返回第 2 个成员值 password
      return this.password;
   }

   @NotNull
   public final LoginUser copy(@NotNull String username, @NotNull String password) {
      Intrinsics.checkNotNullParameter(username, "username");
      Intrinsics.checkNotNullParameter(password, "password");
      return new LoginUser(username, password);
   }

   // $FF: synthetic method
   public static LoginUser copy$default(LoginUser var0, String var1, String var2, int var3, Object var4) {
      if ((var3 & 1) != 0) {
         var1 = var0.username;
      }

      if ((var3 & 2) != 0) {
         var2 = var0.password;
      }

      return var0.copy(var1, var2);
   }

   @NotNull
   public String toString() {
      return "LoginUser(username=" + this.username + ", password=" + this.password + ")";
   }

   public int hashCode() {
      String var10000 = this.username;
      int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;
      String var10001 = this.password;
      return var1 + (var10001 != null ? var10001.hashCode() : 0);
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof LoginUser) {
            LoginUser var2 = (LoginUser)var1;
            if (Intrinsics.areEqual(this.username, var2.username) && Intrinsics.areEqual(this.password, var2.password)) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
}

数据类自动创建的类

编译器会根据主构造函数中声明的属性,自动创建以下 3 个函数。

  • equals() / hashCode() 函数 toString() 格式为 “LoginUser(username=" + this.username + ", password=" + this.password + ")”
  • component1() 和 component2() 函数返回对应下标的属性值,按声明顺序排列
  • copy() 函数:根据旧对象属性重新 newLoginUser(username, password) 一个对象出来。如果这些函数在类中已经被明确定义了,或者从超类中继承而来,编译器就不再生成。

数据类的语法限制

数据类有如下限制:

  • 主构造函数至少包含一个参数
  • 参数必须标识为 val 或者 var
  • 不能为 abstaact、open、sealed 或者 inner
  • 不能继承其他类(但可以实现接口)

另外,数据类可以在解构声明中使用:

data class LoginUser(val username: String, val password: String)

fun main() {
    val loginUser = LoginUser("admin", "admin")
    val (username, password) = loginUser // 解构声明 (username, password)
    println("username = $username, password = $password")
}