代码之家  ›  专栏  ›  技术社区  ›  Troskyvs

scala序列化总是抛出异常,为什么?

  •  2
  • Troskyvs  · 技术社区  · 6 年前

    我有一个小的scala代码snipet:

    @SerialVersionUID(43L) class p(val a:Int=14,val b:Double=3.0) extends Serializable{
    }
    import java.io._
    
    val out = new ObjectOutputStream(new FileOutputStream("my.obj"))
    out.writeObject(new p(5,7))
    out.close()
    
    val in = new ObjectInputStream(new FileInputStream("my.obj"))
    val savedPerson=in.readObject.asInstanceOf[p]
    println(savedPerson.a)
    

    当我在Windows或Mac上运行时,它会打印出一个巨大的异常信息:

    java.io.NotSerializableException: Main$$anon$1
        at java.base/java.io.ObjectOutputStream.writeObject0(Unknown Source)
        at java.base/java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
        at java.base/java.io.ObjectOutputStream.writeSerialData(Unknown Source)
        at java.base/java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
        at java.base/java.io.ObjectOutputStream.writeObject0(Unknown Source)
        at java.base/java.io.ObjectOutputStream.writeObject(Unknown Source)
        at Main$$anon$1.errorFunction(ch09.scala:52)
        at Main$$anon$1.<init>(ch09.scala:110)
        at Main$.main(ch09.scala:1)
        at Main.main(ch09.scala)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.base/java.lang.reflect.Method.invoke(Unknown Source)
        at scala.reflect.internal.util.ScalaClassLoader.$anonfun$run$2(ScalaClassLoader.scala:98)
        at scala.reflect.internal.util.ScalaClassLoader.asContext(ScalaClassLoader.scala:32)
        at scala.reflect.internal.util.ScalaClassLoader.asContext$(ScalaClassLoader.scala:30)
        at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:129)
        at scala.reflect.internal.util.ScalaClassLoader.run(ScalaClassLoader.scala:98)
        at scala.reflect.internal.util.ScalaClassLoader.run$(ScalaClassLoader.scala:90)
        at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:129)
        at scala.tools.nsc.CommonRunner.run(ObjectRunner.scala:22)
        at scala.tools.nsc.CommonRunner.run$(ObjectRunner.scala:21)
        at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:39)
        at scala.tools.nsc.CommonRunner.runAndCatch(ObjectRunner.scala:29)
        at scala.tools.nsc.CommonRunner.runAndCatch$(ObjectRunner.scala:28)
        at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:39)
        at scala.tools.nsc.ScriptRunner.runCompiled(ScriptRunner.scala:170)
        at scala.tools.nsc.ScriptRunner.$anonfun$runScript$1(ScriptRunner.scala:187)
        at scala.tools.nsc.ScriptRunner.$anonfun$runScript$1$adapted(ScriptRunner.scala:187)
        at scala.tools.nsc.ScriptRunner.$anonfun$withCompiledScript$2(ScriptRunner.scala:156)
        at scala.tools.nsc.ScriptRunner.runScript(ScriptRunner.scala:124)
        at scala.tools.nsc.ScriptRunner.runScriptAndCatch(ScriptRunner.scala:200)
        at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:70)
        at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:85)
        at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
        at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:101)
        at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
    

    这是什么错误?我怎么解决呢?我不太明白。 谢谢!

    1 回复  |  直到 6 年前
        1
  •  3
  •   som-snytt    6 年前

    我从堆栈跟踪中看到您正在使用脚本运行程序:

    scala -nc noser.scala

    我把脚本命名为yessir,不,先生,因为没有序列化发生。

    -nc 避免启动编译服务器守护程序。

    如果脚本运行程序没有看到带有main方法的对象,则它会将脚本代码打包到一个类中,该类是它为您构造的main方法的本地类。

    def main(args: Array[String]) = { class anon_class { code } ; new anon_class() }

    您的代码在构造函数中运行,这也不是一个好主意。

    你可以看到这个 -Xprint:typer,flatten . 或试验 -Xprint:all .

    可序列化类具有指向匿名本地类的外部指针,并且匿名类不可序列化。

    也许外部指针只是个错误。否则,请参阅下面的参考资料。它需要一个提示来消除外部指针,例如 final

    我看到有类似的虫子 this one where the enclosing module is captured by a lambda .

    解决方法是将代码放在对象的主方法中,或将所有内容包装在 App

    object Main extends App {
      // code
    }
    

    另一个解决方法是使您的可序列化类 最终的 . 有人在讨论 on this ticket 以及 related 票和 fix