我正在尝试类的最简单的序列化示例:
@serializable class Person(age:Int) {}
val fred = new Person(45)
import java.io._
val out = new ObjectOutputStream(new FileOutputStream("test.obj"))
out.writeObject(fred)
out.close()
抛出异常" java.io.NotSerializableException:Main $$ anon $ 1 $ Person"包在我身上。为什么? 有简单的序列化示例吗? 我也试过
@serializable class Person(nm:String) {
private val name:String=nm
}
val fred = new Person("Fred")
...
并尝试删除@serializable
和其他一些排列。文件" test.obj"创建,大小超过2Kb,内容合理。
阅读" test.obj"回来(从下面的第二个回答)导致
欢迎使用Scala版本2.10.3(Java HotSpot(TM)64位服务器VM, Java 1.7.0_51)。输入表达式以对其进行评估。输入:help 了解更多信息。
阶> import java.io._ import java.io ._
阶> val fis = new FileInputStream(" test.obj")fis: java.io.FileInputStream = java.io.FileInputStream@716ad1b3
阶> val oin = new ObjectInputStream(fis)oin: java.io.ObjectInputStream = java.io.ObjectInputStream@1f927f0a
阶> val p = oin.readObject java.io.WriteAbortedException:writing 中止; java.io.NotSerializableException:Main $$ anon $ 1 at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1354) at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370) 在12) 在 。() 7岁时) 在 。() at $ print() at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) 在scala.tools.nsc.interpreter.IMain $ ReadEvalPrint.call(IMain.scala:734) 在scala.tools.nsc.interpreter.IMain $ Request.loadAndRun(IMain.scala:983) 在scala.tools.nsc.interpreter.IMain.loadAndRunReq $ 1(IMain.scala:573) 在scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:604) 在scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:568) 在scala.tools.nsc.interpreter.ILoop.reallyInterpret $ 1(ILoop.scala:756) 在scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:801) 在scala.tools.nsc.interpreter.ILoop.command(ILoop.scala:713) 在scala.tools.nsc.interpreter.ILoop.processLine $ 1(ILoop.scala:577) 在scala.tools.nsc.interpreter.ILoop.innerLoop $ 1(ILoop.scala:584) 在scala.tools.nsc.interpreter.ILoop.loop(ILoop.scala:587) 在scala.tools.nsc.interpreter.ILoop $$ anonfun $ process $ 1.apply $ mcZ $ sp(ILoop.scala:878) 在scala.tools.nsc.interpreter.ILoop $$ anonfun $ process $ 1.apply(ILoop.scala:833) 在scala.tools.nsc.interpreter.ILoop $$ anonfun $ process $ 1.apply(ILoop.scala:833) 在scala.tools.nsc.util.ScalaClassLoader $ .savingContextLoader(ScalaClassLoader.scala:135) 在scala.tools.nsc.interpreter.ILoop.process(ILoop.scala:833) 在scala.tools.nsc.MainGenericRunner.runTarget $ 1(MainGenericRunner.scala:83) 在scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96) 在scala.tools.nsc.MainGenericRunner $ .main(MainGenericRunner.scala:105) 在scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)引起 by:java.io.NotSerializableException:Main $$ anon $ 1 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347) 在Main $$ anon $ 1.(a.scala:11) 在Main $ .main(a.scala:1) 在Main.main(a.scala) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) 在scala.tools.nsc.util.ScalaClassLoader $$ anonfun $ run $ 1.apply(ScalaClassLoader.scala:71) 在scala.tools.nsc.util.ScalaClassLoader $ class.asContext(ScalaClassLoader.scala:31) 在scala.tools.nsc.util.ScalaClassLoader $ URLClassLoader.asContext(ScalaClassLoader.scala:139) 在scala.tools.nsc.util.ScalaClassLoader $ class.run(ScalaClassLoader.scala:71) 在scala.tools.nsc.util.ScalaClassLoader $ URLClassLoader.run(ScalaClassLoader.scala:139) 在scala.tools.nsc.CommonRunner $ class.run(ObjectRunner.scala:28) 在scala.tools.nsc.ObjectRunner $ .run(ObjectRunner.scala:45) 在scala.tools.nsc.CommonRunner $ class.runAndCatch(ObjectRunner.scala:35) 在scala.tools.nsc.ObjectRunner $ .runAndCatch(ObjectRunner.scala:45) 在scala.tools.nsc.ScriptRunner.scala $ tools $ nsc $ ScriptRunner $$ runCompiled(ScriptRunner.scala:171) 在scala.tools.nsc.ScriptRunner $$ anonfun $ runScript $ 1.apply(ScriptRunner.scala:188) 在scala.tools.nsc.ScriptRunner $$ anonfun $ runScript $ 1.apply(ScriptRunner.scala:188) 在scala.tools.nsc.ScriptRunner $$ anonfun $ withCompiledScript $ 1.apply $ mcZ $ sp(ScriptRunner.scala:157) 在scala.tools.nsc.ScriptRunner $$ anonfun $ withCompiledScript $ 1.apply(ScriptRunner.scala:131) 在scala.tools.nsc.ScriptRunner $$ anonfun $ withCompiledScript $ 1.apply(ScriptRunner.scala:131) 在scala.tools.nsc.util.package $ .trackingThreads(package.scala:51) 在scala.tools.nsc.util.package $ .waitingForThreads(package.scala:35) 在scala.tools.nsc.ScriptRunner.withCompiledScript(ScriptRunner.scala:130) 在scala.tools.nsc.ScriptRunner.runScript(ScriptRunner.scala:188) 在scala.tools.nsc.ScriptRunner.runScriptAndCatch(ScriptRunner.scala:201) 在scala.tools.nsc.MainGenericRunner.runTarget $ 1(MainGenericRunner.scala:76) ......还有3个
答案 0 :(得分:29)
请注意,@serializable
scaladoc告诉它自2.9.0以来已弃用:
不推荐使用(从版本2.9.0开始)而不是@serializable类C,使用类C extends Serializable
所以你只需要使用Serializable
特质:
class Person(val age: Int) extends Serializable
这适用于我(在REPL中键入:paste
并粘贴这些行):
import java.io.{ObjectOutputStream, ObjectInputStream}
import java.io.{FileOutputStream, FileInputStream}
class Person(val age: Int) extends Serializable {
override def toString = s"Person($age)"
}
val os = new ObjectOutputStream(new FileOutputStream("/tmp/example.dat"))
os.writeObject(new Person(22))
os.close()
val is = new ObjectInputStream(new FileInputStream("/tmp/example.dat"))
val obj = is.readObject()
is.close()
obj
这是输出:
// Exiting paste mode, now interpreting.
import java.io.{ObjectOutputStream, ObjectInputStream}
import java.io.{FileOutputStream, FileInputStream}
defined class Person
os: java.io.ObjectOutputStream = java.io.ObjectOutputStream@5126abfd
is: java.io.ObjectInputStream = java.io.ObjectInputStream@41e598aa
obj: Object = Person(22)
res8: Object = Person(22)
所以,你可以看到,[de]序列化尝试成功了。
编辑(关于您从文件运行Scala脚本时获得NotSerializableException
的原因)
我已将我的代码放入文件并尝试通过scala test.scala
运行它并得到与您完全相同的错误。以下是我对其发生原因的猜测。
根据堆栈跟踪,一个奇怪的类Main$$anon$1
不可序列化。逻辑问题是:为什么它首先出现在那里?我们毕竟试图序列化Person
,而不是奇怪的事情。
Scala脚本的特殊之处在于它隐式包装在名为Main
的对象中。这由堆栈跟踪表示:
at Main$$anon$1.<init>(test.scala:9)
at Main$.main(test.scala:1)
at Main.main(test.scala)
这里的名称表明Main.main
静态方法是程序入口点,并且此方法委托给Main$.main
实例方法(object
的类以对象命名但是{附加{1}}。此实例方法依次尝试创建类$
的实例。据我所知,匿名类是这样命名的。
现在,让我们尝试找到准确的Main$$anon$1
类名称(将其作为Scala脚本运行):
Person
这打印出我期待的东西:
class Person(val age: Int) extends Serializable {
override def toString = s"Person($age)"
}
println(new Person(22).getClass)
这意味着class Main$$anon$1$Person
不是顶级课程;相反,它是由编译器生成的匿名类中定义的嵌套类!所以事实上我们有类似的东西:
Person
但是在Scala中,所有嵌套类都是Java中的“嵌套非静态”(或“内部”)类。这意味着这些类始终包含对其封闭类的实例的隐式引用。在这种情况下,封闭类是object Main {
def main(args: Array[String]) {
new { // this is where Main$$anon$1 is generated, and the following code is its constructor body
class Person(val age: Int) extends Serializable { ... }
// all other definitions
}
}
}
。因此,当Java序列化程序尝试序列化Main$$anon$1
时,它会传递地遇到Person
的实例并尝试序列化它,但由于它不是Main$$anon$1
,因此该过程失败。顺便说一下,序列化非静态内部类是Java世界中一个臭名昭着的东西,众所周知会引起像这样的问题。
至于为什么它在REPL中工作,似乎在REPL声明的类中不会以某种方式结束为内部的,因此它们没有任何隐式字段。因此序列化对他们来说是正常的。
答案 1 :(得分:4)
您可以使用Serializable Trait:
使用带有Serializable Trait的Java序列化的简单序列化示例:
case class Person(age: Int) extends Serializable
用法:
序列化,写对象
val fos = new FileOutputStream( "person.serializedObject" )
val o = new ObjectOutputStream( fos )
o writeObject Person(31)
反序列化,读取对象
val fis = new FileInputStream( "person.serializedObject" )
val oin = new ObjectInputStream( fis )
val p= oin.readObject
创建以下输出
fis: java.io.FileInputStream = java.io.FileInputStream@43a2bc95
oin: java.io.ObjectInputStream = java.io.ObjectInputStream@710afce3
p: Object = Person(31)
如您所见,反序列化无法推断出对象类型本身,这是一个明显的缺点。
使用Scala-Pickling进行序列化
https://github.com/scala/pickling或标准分发的一部分,以Scala 2.11开头
在exmple代码中,对象不会写入文件,而是使用JSON而不是ByteCode Serialization,这可以避免源自不同Scala版本之间字节代码不兼容的某些问题。
import scala.pickling._
import json._
case class Person(age: Int)
val person = Person(31)
val pickledPerson = person.pickle
val unpickledPerson = pickledPerson.unpickle[Person]
答案 2 :(得分:1)
class Person(age:Int) {}
等同于Java代码:
class Person{
Person(Int age){}
}
这可能不是你想要的。请注意,参数age
只是被丢弃,Person
没有成员字段。
你想要:
@serializable case class Person(age:Int)
@serializable class Person(val age:Int)
您可以在末尾省略空的花括号。事实上,它受到了鼓励。