【问题标题】:case class private constructor - need for readResolve implementationcase 类私有构造函数 - 需要 readResolve 实现
【发布时间】:2015-11-21 01:57:17
【问题描述】:

我只是在谷歌上搜索,以了解如何使用私有构造函数创建案例类。以下是正确的方法,如

中所述

How to override apply in a case class companion

object A {
  def apply(s: String, i: Int): A =
    new A(s.toUpperCase, i) {} //abstract class implementation intentionally empty
}
abstract case class A private[A] (s: String, i: Int) {
  private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
    A.apply(s, i)
  def copy(s: String = s, i: Int = i): A =
    A.apply(s, i)
}

以下是我目前的理解:-

如果我们声明了一个case类抽象,那么编译器就不会生成copy和apply方法的实现。

以下是我正在努力解决的问题:-

为什么需要提供 readResolve 的实现?

【问题讨论】:

  • 我是您最初提出这个问题的另一个线程上答案的作者。我正在遵循基于 Joshua Bloch 在他的“Effective Java, 2nd Edition”一书中的建议的 JVM/Java 最佳实践。原帖:stackoverflow.com/a/25538287/501113
  • 顺便说一句,为了更全面地了解 JVM/Java readResolve 方法和案例类的特殊性,这是我编写的文档(连同 CodeReview 更新),它深入探讨了为什么我希望始终防止实例化案例类的无效实例:docs.google.com/document/d/…

标签: scala constructor private


【解决方案1】:

readResolve 实现用于通过编辑类的序列化副本来防止创建案例类的无效实例。

根据您对使用代码的环境的信任程度,您可能会觉得可以放心地忽略此风险。

它的出现是因为案例类扩展了Serializable,因此最终可能会被序列化并写入文件(或数据库,或任何地方)。此时可以编辑文件/DB/wherever 中的序列化副本以创建无效值(例如,将s 设为小写)。在反序列化后,“活动”实例将无效,除非在反序列化过程中使用的 readResolve 方法被覆盖以防止这种情况发生。

【讨论】:

  • 无论我的案例类类型(抽象或非抽象)如何,我都可以考虑将 readResolve 实现为最佳实践吗?如果我的案例类不是抽象的,那么 scala 编译器会负责 readResolve 的实现吗?
  • @rits 标准的 Java 反序列化过程从正在读取的流中实例化实例(基本上只是读取和设置实例的各个字段),然后检查是否定义了 readResolve 方法。如果是,则调用它,并将其结果用作正在构建的实例的替代品。这种机制为类设计者提供了修改或完全替换读入实例的机会(此处确保s 始终为大写)。因此,默认情况下,通常不需要实现 readResolve。
  • Scala 遵循默认的 JVM/Java 标准库进行序列化。因此,更多的是关于 JVM/Java 的最佳实践。由于序列化以许多不同的方式使用,包括但不限于文件读/写、网络套接字流读/写、JVM 进程间读/写(尽管这已经过时了,因为操作系统现在通过当它们位于同一“机器”中时的网络套接字)。等等。因此,在 Scala 中应用与在该领域使用 Java 相同的原则。
猜你喜欢
  • 1970-01-01
  • 2011-02-04
  • 1970-01-01
  • 2014-04-23
  • 2013-10-25
  • 2023-04-09
  • 2014-01-30
  • 2011-04-20
  • 1970-01-01
相关资源
最近更新 更多