为什么案例对象可序列化而案例类不是?

Mar*_*sco 11 serialization scala remote-actors case-class

我正在使用这个示例http://scala.sygneca.com/code/remoteactors来学习远程演员如何在Scala中工作(2.8.0).特别是我稍微修改了演员发送的消息如何定义如下:

sealed trait Event extends Serializable
case object Ping extends Event
case object Pong extends Event
case object Quit extends Event
Run Code Online (Sandbox Code Playgroud)

一切都按预期工作.不幸的是,如果我将事件定义为案例类而不是案例对象,如:

sealed trait Event extends Serializable
case class Ping extends Event
case class Pong extends Event
case class Quit extends Event
Run Code Online (Sandbox Code Playgroud)

我的例子停止工作.更详细地说,虽然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$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)
Run Code Online (Sandbox Code Playgroud)

是否有理由可以使case对象可序列化,而case类不能?有没有办法让我的例子使用案例类?

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

public class scalachat.remote.Ping extends java.lang.Object implements scalachat.remote.Event,java.io.Serializable,scala.ScalaObject,scala.Product
Run Code Online (Sandbox Code Playgroud)

伴侣对象不是:

public final class scalachat.remote.Ping$ extends scala.runtime.AbstractFunction0 implements scala.ScalaObject
Run Code Online (Sandbox Code Playgroud)

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

pong ! Ping()
Run Code Online (Sandbox Code Playgroud)

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

case class Ping(i: Int) extends Event
Run Code Online (Sandbox Code Playgroud)

发送消息为:

pong ! Ping(0)
Run Code Online (Sandbox Code Playgroud)

但没有经历任何差异.有什么建议吗?

Vik*_*ang 15

@serializable case class Foo
Run Code Online (Sandbox Code Playgroud)

我也很惊讶,默认情况下,case对象是可序列化的.

编辑:正确阅读例外后我怀疑:

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

  • 案例类也是可序列化的.顺便说一句,在上面的案例类的片段中继承自`Serializable`,在大多数情况下等于使用`@ serializable`注释 (9认同)
  • 一般来说,不建议使用`@ serializable`,它很快就会被弃用:http://scala-programming-language.1934581.n4.nabble.com/deprecate-serializable-td3002109.html (7认同)
  • 为了澄清Viktor的编辑,看起来你正在调用`writeObject(Ping)`而不是`writeObject(Ping())`. (4认同)