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

发布于 2024-09-30 13:30:56 字数 2606 浏览 9 评论 0原文

我正在玩这个例子 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

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

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

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

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)

是否存在案例对象可以序列化而案例类不能序列化的原因?有没有办法让我的示例与案例类一起使用?

编辑:根据 Victor 的建议并由 Aaron 确认,我将伴随对象作为消息而不是类发送。此外,使用 javap 检查编译后的代码,很明显,虽然类是可序列化的:但

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

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

pong ! Ping()

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

case class Ping(i: Int) extends Event

发送消息为:

pong ! Ping(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

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)

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?

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:

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:

pong ! Ping()

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

case class Ping(i: Int) extends Event

sending the message as:

pong ! Ping(0)

but without experiencing any difference still. Any suggestion?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

只为一人 2024-10-07 13:30:56
@serializable case class Foo

我还感到惊讶的是,案例对象默认是可序列化的。

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

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

@serializable case class Foo

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

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.

橘和柠 2024-10-07 13:30:56

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文