Scala - 可变HashMap - >写入文件/从文件中读取 - > HashMap null

时间:2013-03-07 16:35:36

标签: android scala serialization hashmap deserialization

我在Android设备上运行此Scala代码:

// create Map
val myMap1 = new HashMap[Int, String]()
myMap1.put(1, "a")

// write it to file
val outStream = context.openFileOutput("test.txt", Context.MODE_PRIVATE)
val ostream = new ObjectOutputStream(outStream)
ostream.writeObject(myMap1)
ostream.close

// read from file
val inStream = context.openFileInput("test.txt")
val istream = new ObjectInputStream(inStream)
val myMap2 = (istream.readObject).asInstanceOf[HashMap[Int, String]]
istream.close

// java.lang.NullPointerException accessing myMap2
if (myMap2.contains(1)) { println("yes") } else { println("no") }

我创建了一个mutable.HashMap并将其写入文件,读取它然后HashMap为null。为什么myMap2为空并且没有任何内容?下面是调试会话的屏幕截图。

Screenshot of Eclipse IDE - debug session

完整的堆栈跟踪:

java.lang.NullPointerException
  at scala.collection.mutable.HashTable$class.index(HashTable.scala:353)
  at scala.collection.mutable.HashMap.index(HashMap.scala:39)
  at scala.collection.mutable.HashTable$class.findEntry(HashTable.scala:130)
  at scala.collection.mutable.HashMap.findEntry(HashMap.scala:39)
  at scala.collection.mutable.HashMap.contains(HashMap.scala:60)
  at com.test.mytest.bean.MyItem$.read(MyItem.scala:74)
  at com.test.mytest.bean.MyItem$.add(MyItem.scala:93)
  at com.test.mytest.frag.MyFragment.onClick(MyFragment.scala:114)
  at android.view.View.performClick(View.java:4084)
  at android.view.View$PerformClick.run(View.java:16966)
  at android.os.Handler.handleCallback(Handler.java:615)
  at android.os.Handler.dispatchMessage(Handler.java:92)
  at android.os.Looper.loop(Looper.java:137)
  at android.app.ActivityThread.main(ActivityThread.java:4745)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:511)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
  at dalvik.system.NativeStart.main(Native Method)

1 个答案:

答案 0 :(得分:3)

原因是HashTable包含一个被声明为“瞬态”的受保护字段table

@transient protected var table: Array[HashEntry[A, Entry]]

因此,它永远不会写入文件,并且反序列化时会保留其默认的null值。

然而,HashMap定义了readObjectwriteObject来明确地处理序列化(我没有花时间在整个代码中潜水但是大多数情况下这应该处理读数/写table字段等等,所以它似乎应该工作。

现在,让我在这里做一个有根据的猜测:你在Android上,所以你肯定使用像proguard这样的工具来删除所有不需要的代码(并通过重命名缩小你需要的代码)。问题是readObjectwriteObject是私有的,因此根据你的proguard配置,proguard可能会假定从不访问这些方法,因此完全删除它们。因此,在运行时,只使用标准序列化,并且应该处理应该处理table的自定义序列化。

您应该做的是修改您的proguard配置,以便保留readObjectwriteObject方法。标准的proguard文档甚至在这里有一个例子(搜索“readObject”):http://proguard.sourceforge.net/index.html#manual/examples.html