2010-12-01 24 views
2

我有一個集合的實例,我想要外部存儲然後恢復到原始集合類型。例如我如何反思性地創建新集合?

class Foo { 
    var x : List[Int] 
} 

val f = new Foo 
f.x = List(1, 2, 3) 

我「連載」輸出F,我要反思創建一個新富,F2,並用正確的結果填充F2.X。

我可以通過做classOf[Foo].newInstance來創建新的Foo,但是如何創建正確的集合類型並填充它?我知道fx的類型,我甚至可以序列化出類型 2)我將x的內容序列化爲保留值的東西 3)我不想使用任何「標準」序列化

我試圖使用原始集合上的可用構建器,但我不太明白它是如何工作足以把它拉開。

感謝,

戴夫

+0

類代碼`Foo`不編譯...如果你想有一個具體的類,你應該不會遺漏任何抽象成員。 – axel22 2010-12-01 09:00:16

回答

1

它會更容易,如果我們有你想要解決的問題,例如更好的主意,以幫助這裏爲什麼你不想使用標準對象序列化。

這就是說,如果你真的想這樣做反射在斯卡拉集合類,你可能需要知道的幾件事斯卡拉目前如何編譯的類和對象:

  • 如果你想List對象的類(不適用於List類),名稱爲scala.collection.immutable.List$ - 請注意最終的美元符號。

  • 如果您想要單例列表對象實例,它存儲爲字段MODULE$

  • 大多數斯卡拉集合同伴對象提供一個newBuilder方法,創建具有+=$plus$eq)方法和result方法允許你創建一個新的集合對象。

所以,你可以這樣做:

scala> def buildByReflection[T](collectionClassName: String, items: Array[T]) = { 
    | val companionClass = Class.forName(collectionClassName + "$") 
    | val companion = companionClass.getField("MODULE$").get(null) 
    | val newBuilder = companionClass.getMethod("newBuilder") 
    | val builder = newBuilder.invoke(companion) 
    | val plusEq = builder.getClass.getMethod("$plus$eq", classOf[Object]) 
    | for (item <- items) { 
    |  plusEq.invoke(builder, item.asInstanceOf[AnyRef]) 
    | } 
    | builder.getClass.getMethod("result").invoke(builder) 
    | } 
buildByReflection: [T](collectionClassName: String,items: Array[T])java.lang.Object 

scala> buildByReflection("scala.collection.immutable.List", Array(1, 2, 3)) 
res0: java.lang.Object = List(1, 2, 3)