为什么 case 对象可序列化而 case 类不可序列化? [英] Why are case objects serializable and case classes not?
问题描述
我正在使用这个示例 http://scala.sygneca.com/code/remoteactors 了解远程 actor 在 Scala (2.8.0) 中的工作方式.特别是,我稍微修改了参与者发送的消息的定义方式,如下所示:
I am playing with this example http://scala.sygneca.com/code/remoteactors to 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:
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
我的示例停止工作.更详细地说,虽然 case 对象是可序列化的,但 case 类不是.事实上,当我尝试使用最后一次修改运行我的示例时,我得到以下异常:
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:
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$1$$anonfun$apply$1.apply(Proxy.scala:182)
at scala.actors.remote.DelegateActor$$anonfun$act$1$$anonfun$apply$1.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)
case 对象可以序列化而 case 类不能序列化的原因是什么?有没有办法让我的示例与案例类一起工作?
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?
按照 Victor 的建议并由 Aaron 确认,我将伴随对象作为消息而不是类发送.此外,使用 javap 检查编译后的代码似乎很明显,虽然该类是可序列化的:
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:
public class scalachat.remote.Ping extends java.lang.Object implements scalachat.remote.Event,java.io.Serializable,scala.ScalaObject,scala.Product
伴随对象不是:
public final class scalachat.remote.Ping$ extends scala.runtime.AbstractFunction0 implements scala.ScalaObject
现在的问题是:如何指定我要使用类而不是伴随对象?当我按照 Aaron 的建议发送消息时,我还添加了一对空括号,例如:
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:
pong ! Ping()
但没有任何改变.最后我还给case类加了一个假参数
but nothing is changed. In the end I also added a fake parameter to the case class
case class Ping(i: Int) extends Event
发送消息为:
pong ! Ping(0)
但仍然没有任何区别.有什么建议吗?
but without experiencing any difference still. Any suggestion?
推荐答案
@serializable case class Foo
我也很惊讶 case 对象默认是可序列化的.
I was also surprised that case objects were serializable per default.
正确阅读异常后,我怀疑:
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.
这篇关于为什么 case 对象可序列化而 case 类不可序列化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!