2

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 になります。なぜmyMap2null でコンテンツがないのですか? 以下は、デバッグ セッションのスクリーンショットです。

Eclipse IDE のスクリーンショット - デバッグ セッション

完全なスタック トレース:

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)
4

1 に答える 1

3

その理由は、「一時的」として宣言さHashTableれた保護フィールドが含まれているためです。table

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

したがって、ファイルに書き込まれることはなく、逆シリアル化してもデフォルトnull値が保持されます。

ただし、シリアル化をHashMap定義readObjectwriteObjectて明示的に処理するため(コード全体を詳しく説明するのに時間をかけていませんが、tableフィールドの読み取り/書き込みなどを処理することになっていることは間違いありません)、とにかく機能するはずです。

さて、ここで知識に基づいた推測をしましょう。あなたはAndroidを使用しているので、間違いなくproguardなどのツールを使用して、不要なコードをすべて削除します(そして、名前を変更して必要なコードを縮小します)。問題は、readObjectwriteObjectがプライベートであるということです。したがって、proguardの構成によっては、proguardはメソッドがアクセスされないと想定し、メソッドを完全に削除する場合があります。したがって、実行時には、標準のシリアル化のみが使用され、処理することになっているカスタムのシリアル化はtable発生しません。

readObjectとメソッドを保持するように、proguard構成を変更する必要がありwriteObjectます。標準のproguardドキュメントには、この例もあります(「readObject」を検索してください):http://proguard.sourceforge.net/index.html#manual/examples.html

于 2013-03-07T17:25:03.847 に答える