【问题标题】:How does Firestore's `documentSnapshot.toObject(className::class.java)` reassign `val` values that were set in the primary constructor?Firestore 的 `documentSnapshot.toObject(className::class.java)` 如何重新分配在主构造函数中设置的 `val` 值?
【发布时间】:2019-05-12 11:24:14
【问题描述】:

我一直在开发 Kotlin 后端服务,偶然发现了 Firestore documentSnapshot.toObject(className::class.java) 方法。

拿下面的 Kotlin data class:

data class Record(
        val firstName: String = "",
        val lastName: String = "",
        val city: String = "",
        val country: String = "",
        val email: String = "")

以下代码来自我的Repository 类:

if (documentSnapshot.exists()) {
    return documentSnapshot.toObject(Record::class.java)!!
}

现在,据我了解,documentSnapshot.toObject(className::class.java) 方法需要并调用无参数默认构造函数,例如val record = Record()

此调用将调用主构造函数并将其中规定的默认值(在数据类Record 的情况下,空字符串"")分配给字段。

然后,它使用公共 setter 方法将实例的字段设置为在 document 中找到的值。

鉴于字段已在主数据类构造函数中标记为val,这怎么可能? 反射在这里起作用吗? val 不是真正在 Kotlin 中的最终版本吗?

【问题讨论】:

标签: firebase kotlin google-cloud-firestore data-class


【解决方案1】:

Firebase 确实使用反射来设置/获取值。具体来说,它使用 JavaBean 模式来识别属性,然后使用它们的 publicgetter/setter 或使用 public 字段来获取/设置它们。

你的 data class 被编译成这个 Java 代码的等价物:

public static final class Record {
  @NotNull
  private final String firstName;
  @NotNull
  private final String lastName;
  @NotNull
  private final String city;
  @NotNull
  private final String country;
  @NotNull
  private final String email;

  @NotNull
  public final String getFirstName() { return this.firstName; }
  @NotNull
  public final String getLastName() { return this.lastName; }
  @NotNull
  public final String getCity() { return this.city; }
  @NotNull
  public final String getCountry() { return this.country; }
  @NotNull
  public final String getEmail() { return this.email; }

  public Record(@NotNull String firstName, @NotNull String lastName, @NotNull String city, @NotNull String country, @NotNull String email) {
     Intrinsics.checkParameterIsNotNull(firstName, "firstName");
     Intrinsics.checkParameterIsNotNull(lastName, "lastName");
     Intrinsics.checkParameterIsNotNull(city, "city");
     Intrinsics.checkParameterIsNotNull(country, "country");
     Intrinsics.checkParameterIsNotNull(email, "email");
     super();
     this.firstName = firstName;
     this.lastName = lastName;
     this.city = city;
     this.country = country;
     this.email = email;
  }

  ...

}

在这种情况下,当我需要将属性值写入数据库时​​,Firebase 使用公共 getter 来获取属性值,并在从数据库中读取属性值时使用字段来设置属性值。

【讨论】:

  • 更具体地说,每个 val 都被赋予一个默认值这一事实让 Kotlin 创建了一个无参数构造函数,它允许 Firebase SDK 首先实例化数据类,而无需必须知道它可以持有的所有值。所以你最终会得到public Record() {...} 以及主构造函数和所有访问器。
  • 感谢您澄清道格。我想知道为什么它有一个默认构造函数,而其他 data class 示例没有。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-08
  • 2019-12-03
  • 1970-01-01
  • 1970-01-01
  • 2020-08-03
  • 1970-01-01
  • 2018-03-15
相关资源
最近更新 更多