scala 为什么 case 对象可序列化而 case 类不可序列化?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4067792/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:32:37  来源:igfitidea点击:

Why are case objects serializable and case classes not?

serializationscalacase-classremote-actors

提问by Mario Fusco

I am playing with this example http://scala.sygneca.com/code/remoteactorsto learn how remote actors work in Scala (2.8.0). In particular I slightly modified how the messages send by the actors are defined as it follows:

我正在使用这个示例http://scala.sygneca.com/code/remoteactors来了解远程 actor 在 Scala (2.8.0) 中的工作方式。特别是,我稍微修改了参与者发送的消息的定义方式,如下所示:

sealed trait Event extends Serializable
case object Ping extends Event
case object Pong extends Event
case object Quit extends Event

and everything works as expected. Unfortunately if I define the events as case classes instead of case objects as in:

一切都按预期进行。不幸的是,如果我将事件定义为案例类而不是案例对象,如下所示:

sealed trait Event extends Serializable
case class Ping extends Event
case class Pong extends Event
case class Quit extends Event

my example stop working. In more detail it seems that while case objects are serializable, case classes aren't. Indeed when I try to run my example with this last modification I get the following exception:

我的例子停止工作。更详细地说,虽然 case 对象是可序列化的,但 case 类不是。实际上,当我尝试使用最后一次修改运行我的示例时,我收到以下异常:

scala.actors.remote.DelegateActor@148cc8c: caught java.io.NotSerializableException: scalachat.remote.Ping$
java.io.NotSerializableException: scalachat.remote.Ping$
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
    at scala.actors.remote.JavaSerializer.serialize(JavaSerializer.scala:46)
    at scala.actors.remote.NetKernel.namedSend(NetKernel.scala:38)
    at scala.actors.remote.NetKernel.forward(NetKernel.scala:71)
    at scala.actors.remote.DelegateActor$$anonfun$act$$anonfun$apply.apply(Proxy.scala:182)
    at scala.actors.remote.DelegateActor$$anonfun$act$$anonfun$apply.apply(Proxy.scala:123)
    at scala.actors.ReactorTask.run(ReactorTask.scala:34)
    at scala.actors.ReactorTask.compute(ReactorTask.scala:66)
    at scala.concurrent.forkjoin.RecursiveAction.exec(RecursiveAction.java:147)
    at scala.concurrent.forkjoin.ForkJoinTask.quietlyExec(ForkJoinTask.java:422)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.mainLoop(ForkJoinWorkerThread.java:340)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:325)

Is there a reason why case objects can be made serializable and case classes can't? Is there a way to make my example working with case classes either?

是否有理由可以使 case 对象可序列化而 case 类不能?有没有办法让我的示例与案例类一起工作?

Edit: as suggested by Victor and confirmed by Aaron I am sending the companion object as message instead of the class. Moreover inspecting the compiled code with javap it appears evident that while the class is serializable:

编辑:按照维克多的建议并由亚伦确认,我将伴随对象作为消息而不是类发送。此外,使用 javap 检查编译后的代码似乎很明显,虽然该类是可序列化的:

public class scalachat.remote.Ping extends java.lang.Object implements scalachat.remote.Event,java.io.Serializable,scala.ScalaObject,scala.Product

the companion object is not:

伴随对象不是:

public final class scalachat.remote.Ping$ extends scala.runtime.AbstractFunction0 implements scala.ScalaObject

Now the question is: how can I specify that I want to use the class instead of the companion object? I also added an empty couple of parenthesis when I send the message as suggested by Aaron like in:

现在的问题是:如何指定我要使用该类而不是伴随对象?当我按照 Aaron 的建议发送消息时,我还添加了一对空括号,如下所示:

pong ! Ping()

but nothing is changed. In the end I also added a fake parameter to the case class

但没有任何改变。最后我还在case类中添加了一个假参数

case class Ping(i: Int) extends Event

sending the message as:

发送消息为:

pong ! Ping(0)

but without experiencing any difference still. Any suggestion?

但仍然没有任何区别。有什么建议吗?

回答by Viktor Klang

@serializable case class Foo

I was also surprised that case objects were serializable per default.

我也很惊讶 case 对象默认是可序列化的。

Edit: After reading the exception properly I suspect that:

编辑:正确阅读异常后,我怀疑:

You're trying to send the generated companion object of the case class over the wire, instead of an instance of the case class.

您正在尝试通过网络发送案例类的生成伴随对象,而不是案例类的实例。

回答by Daniel C. Sobral

Case classes without parameters are meaningless and deprecated. And I see no Serializablein Scala, just serializable. Does it work if you fix these things?

没有参数的案例类是没有意义的并且已被弃用。我Serializable在 Scala 中没有看到,只有serializable. 如果你解决这些问题,它会起作用吗?